This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2goclient. commit df4a8ec7f4c2d19dac358579fdb246b9900f1cee Author: Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> Date: Tue Jul 13 10:50:31 2021 +0200 Support for HTTP(S) urls in the session icons when using http broker. --- debian/changelog | 1 + src/folderbutton.cpp | 21 ++++----- src/httpbrokerclient.cpp | 112 ++++++++++++++++++++++++++++++++++++++++++++++- src/httpbrokerclient.h | 6 +++ src/sessionbutton.cpp | 13 +++++- 5 files changed, 140 insertions(+), 13 deletions(-) diff --git a/debian/changelog b/debian/changelog index e7c8a85..388983b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -20,6 +20,7 @@ x2goclient (4.1.2.3-0x2go1) UNRELEASED; urgency=medium - X2Go Client will send it's OS name to the broker when sending client event. - Don't exit if connection to HTTP broker is failed when sync sessions. + - Support for HTTP(S) urls in the session icons when using http broker. [ Ryan Schmidt ] * New upstream version (4.1.2.3): diff --git a/src/folderbutton.cpp b/src/folderbutton.cpp index c0d4016..9f2211f 100644 --- a/src/folderbutton.cpp +++ b/src/folderbutton.cpp @@ -106,24 +106,25 @@ void FolderButton::loadIcon() else st= new X2goSettings( "sessions" ); - QString sessIcon=par->iconsPath("/128x128/folder.png"); - QPixmap* pix; + QPixmap* pix=new QPixmap(); QString normPath=(path+"/"+name).split("/",QString::SkipEmptyParts).join("::"); - - QByteArray picture = QByteArray::fromBase64( st->setting()->value ( "icon_"+normPath, - ( QVariant )QString()).toString().toLocal8Bit()); - if(!picture.size()) + QString picURL=st->setting()->value ( "icon_"+normPath, ( QVariant )QString()).toString(); + if(picURL.indexOf("file://")!=-1) { - pix=new QPixmap( sessIcon ); + //load icon from file URL + pix->load(picURL.replace("file://","")); } else { - pix=new QPixmap(); - pix->loadFromData(picture); + pix->loadFromData(QByteArray::fromBase64( picURL.toLocal8Bit())); + } + if(pix->isNull()) + { + //loading icon has failed, load default icon + pix->load(par->iconsPath("/128x128/folder.png")); } bool miniMode=par->retMiniMode(); - if ( !miniMode ) { icon->setPixmap ( pix->scaled ( 64,64,Qt::IgnoreAspectRatio, diff --git a/src/httpbrokerclient.cpp b/src/httpbrokerclient.cpp index fa66613..88fbdc3 100644 --- a/src/httpbrokerclient.cpp +++ b/src/httpbrokerclient.cpp @@ -19,6 +19,7 @@ #include <QNetworkAccessManager> #include <QUrl> #include <QNetworkRequest> +#include <QNetworkDiskCache> #include <QNetworkReply> #include <QUuid> #include <QTextStream> @@ -74,7 +75,12 @@ HttpBrokerClient::HttpBrokerClient ( ONMainWindow* wnd, ConfigFile* cfg ) x2goDebug<<"Custom CA certificate file loaded into HTTPS broker client: "<<config->brokerCaCertFile; } + QDir dr; + dr.mkpath(mainWindow->getHomeDirectory()+"/.x2go"); http=new QNetworkAccessManager ( this ); + QNetworkDiskCache *cache = new QNetworkDiskCache(this); + cache->setCacheDirectory(mainWindow->getHomeDirectory()+"/.x2go/cache"); + http->setCache(cache); x2goDebug<<"Setting up connection to broker: "<<config->brokerurl; connect ( http, SIGNAL ( sslErrors ( QNetworkReply*, const QList<QSslError>& ) ),this, @@ -541,7 +547,39 @@ void HttpBrokerClient::createIniFile(const QString& raw_content) cont=lines[1]; cont=cont.split("END_USER_SESSIONS\n")[0]; } - mainWindow->config.iniFile=cont; + + if(!sshBroker) + { + QStringList iniLines=cont.split("\n"); + cont.clear(); + clearResRequests(); + //check if some of the icon or icon_foldername values are URLs and need to be downloaded + foreach(QString ln, iniLines) + { + ln=ln.trimmed(); + if(ln.indexOf("icon")==0) + { + QStringList lnParts=ln.split("="); + QString iconUrl=lnParts.last().trimmed(); + if((iconUrl.indexOf("http://")!=-1)||(iconUrl.indexOf("https://")!=-1)) + { + ln=lnParts[0]+"=file://"+getResource(iconUrl); + } + } + cont+=ln+"\n"; + } + mainWindow->config.iniFile=cont; + if(resReplies.count()==0) + { + //we didn't request any resources, all session info is loaded + emit sessionsLoaded(); + } + } + else + { + mainWindow->config.iniFile=cont; + emit sessionsLoaded(); + } lines=content.split("START_CLIENT_CONFIG\n"); if (lines.count()>1) { @@ -556,6 +594,52 @@ void HttpBrokerClient::createIniFile(const QString& raw_content) } +//get the fname on disk from resource URL +QString HttpBrokerClient::resourceFname(const QUrl& url) +{ + QString fname=url.toString(); + fname.replace("http://",""); + fname.replace("https://",""); + fname.replace("/","_"); + QDir dr; + dr.mkdir(mainWindow->getHomeDirectory()+"/.x2go/res"); + return mainWindow->getHomeDirectory()+"/.x2go/res/"+fname; +} + +//return true if the URL is already requested +bool HttpBrokerClient::isResRequested(const QUrl& url) +{ + foreach(QNetworkReply* reply, resReplies) + { + if(reply->url().toString()==url.toString()) + { + return true; + } + } + return false; +} + +//download resource if needed and return the name on the disk +QString HttpBrokerClient::getResource(QString resURL) +{ + QUrl url(resURL); + if(!isResRequested(url)) + { + resReplies << http->get(QNetworkRequest(url)); + } + return resourceFname(url); +} + +//clear list of res requests +void HttpBrokerClient::clearResRequests() +{ + foreach(QNetworkReply* reply, resReplies) + { + reply->deleteLater(); + } + resReplies.clear(); +} + bool HttpBrokerClient::checkAccess(QString answer ) { // x2goDebug<<"Called checkAccess - answer was: "<<answer; @@ -616,7 +700,6 @@ void HttpBrokerClient::slotListSessions(bool success, QString answer, int) mainWindow->setBrokerStatus(tr("Connected to broker")); createIniFile(answer); - emit sessionsLoaded(); } void HttpBrokerClient::slotPassChanged(bool success, QString answer, int) @@ -651,6 +734,30 @@ void HttpBrokerClient::slotSelectSession(bool success, QString answer, int) void HttpBrokerClient::slotRequestFinished ( QNetworkReply* reply ) { + if(resReplies.indexOf(reply) != -1) + { + if(reply->error() != QNetworkReply::NoError) + { + x2goDebug<<"Download request for "<<reply->url().toString()<< " failed with error: "<<reply->errorString(); + } + else + { +// x2goDebug<<"saving to "<<resourceFname(reply->url().toString())<<" from cache: "<<reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool(); + QFile file(resourceFname(reply->url().toString())); + file.open(QIODevice::WriteOnly); + file.write(reply->readAll()); + file.close(); + } + foreach(QNetworkReply* r, resReplies) + { + if(!r->isFinished()) + { + return; + } + } + emit sessionsLoaded(); + return; + } if(reply->error() != QNetworkReply::NoError) { x2goDebug<<"Broker HTTP request failed with error: "<<reply->errorString(); @@ -698,6 +805,7 @@ void HttpBrokerClient::slotRequestFinished ( QNetworkReply* reply ) slotEventSent(true,answer,0); } + // We receive ownership of the reply object // and therefore need to handle deletion. reply->deleteLater(); diff --git a/src/httpbrokerclient.h b/src/httpbrokerclient.h index f1ad345..bb15720 100644 --- a/src/httpbrokerclient.h +++ b/src/httpbrokerclient.h @@ -57,6 +57,8 @@ private: QNetworkReply* chPassRequest; QNetworkReply* testConRequest; QNetworkReply* eventRequest; + //List of replies with http resources (icons) + QList<QNetworkReply*> resReplies; QString nextAuthId; QString newBrokerPass; ConfigFile* config; @@ -72,6 +74,10 @@ private: void createSshConnection(); bool checkAccess(QString answer); QString scramblePwd(const QString& req); + QString getResource(QString resURL); + QString resourceFname(const QUrl& url); + bool isResRequested(const QUrl& url); + void clearResRequests(); private slots: void slotRequestFinished ( QNetworkReply* reply ); diff --git a/src/sessionbutton.cpp b/src/sessionbutton.cpp index 0a46ee6..bfccf2a 100644 --- a/src/sessionbutton.cpp +++ b/src/sessionbutton.cpp @@ -373,7 +373,18 @@ void SessionButton::redraw() else { pix=new QPixmap; - pix->loadFromData(QByteArray::fromBase64(sessIcon.toLatin1())); + if(sessIcon.indexOf("file://")!=-1) + { + //load icon from file URL + pix->load(sessIcon.replace("file://","")); + } + else + pix->loadFromData(QByteArray::fromBase64(sessIcon.toLatin1())); + if(pix->isNull()) + { + //loading icon has failed, load default icon + pix->load(par->iconsPath("/128x128/x2gosession.png")); + } } if ( !par->retMiniMode() ) icon->setPixmap ( pix->scaled ( 64,64,Qt::IgnoreAspectRatio, -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2goclient.git