diff --git a/libretroshare/src/retroshare/rsinit.h b/libretroshare/src/retroshare/rsinit.h index c071d4caf..a7cb95b22 100644 --- a/libretroshare/src/retroshare/rsinit.h +++ b/libretroshare/src/retroshare/rsinit.h @@ -127,8 +127,9 @@ class RsInit static std::string RsConfigDirectory(); static std::string RsConfigKeysDirectory(); - static std::string RsProfileConfigDirectory(); - static bool setStartMinimised() ; + static std::string RsProfileConfigDirectory(); + static bool getStartMinimised() ; + static std::string getRetroShareLink(); static int getSslPwdLen(); static bool getAutoLogin(); diff --git a/libretroshare/src/rsserver/rsinit.cc b/libretroshare/src/rsserver/rsinit.cc index f924e8605..4cb8df716 100644 --- a/libretroshare/src/rsserver/rsinit.cc +++ b/libretroshare/src/rsserver/rsinit.cc @@ -127,6 +127,8 @@ class RsInitConfig static std::string load_trustedpeer_file; static bool udpListenerOnly; + + static std::string RetroShareLink; }; @@ -160,6 +162,7 @@ std::string RsInitConfig::passwd; bool RsInitConfig::autoLogin; /* autoLogin allowed */ bool RsInitConfig::startMinimised; /* Icon or Full Window */ +std::string RsInitConfig::RetroShareLink; /* Win/Unix Differences */ char RsInitConfig::dirSeperator; @@ -396,7 +399,7 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck /* getopt info: every availiable option is listed here. if it is followed by a ':' it needs an argument. If it is followed by a '::' the argument is optional. */ - while((c = getopt(argc, argv,"hesamui:p:c:w:l:d:U:")) != -1) + while((c = getopt(argc, argv,"hesamui:p:c:w:l:d:U:r:")) != -1) { switch (c) { @@ -466,6 +469,11 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck std::cerr << "Opt for User Id "; std::cerr << std::endl; break; + case 'r': + RsInitConfig::RetroShareLink = optarg; + std::cerr << "Opt for RetroShare link"; + std::cerr << std::endl; + break; case 'h': std::cerr << "Help: " << std::endl; std::cerr << "The commandline options are for retroshare-nogui, a headless server in a shell, or systems without QT." << std::endl << std::endl; @@ -481,14 +489,15 @@ int RsInit::InitRetroShare(int argcIgnored, char **argvIgnored, bool strictCheck std::cerr << "-u Only listen to UDP" << std::endl; std::cerr << "-e Use a forwarded external Port" << std::endl ; std::cerr << "-U [User Name/GPG id/SSL id] Sets Account to Use, Useful when Autologin is enabled." << std::endl; + std::cerr << "-r link Use RetroShare link." << std::endl; exit(1); break; default: - if (strictCheck) { + if (strictCheck) { std::cerr << "Unknown Option!" << std::endl; std::cerr << "Use '-h' for help." << std::endl; exit(1); - } + } } } @@ -1657,11 +1666,16 @@ std::string RsInit::RsProfileConfigDirectory() return dir; } -bool RsInit::setStartMinimised() +bool RsInit::getStartMinimised() { return RsInitConfig::startMinimised; } +std::string RsInit::getRetroShareLink() +{ + return RsInitConfig::RetroShareLink; +} + int RsInit::getSslPwdLen(){ return SSLPWD_LEN; } diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 1f47e1316..058f0d815 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -246,6 +246,7 @@ HEADERS += rshare.h \ util/PixmapMerging.h \ util/MouseEventFilter.h \ util/EventFilter.h \ + util/EventReceiver.h \ util/Widget.h \ util/rsversion.h \ util/RsAction.h \ @@ -475,6 +476,7 @@ SOURCES += main.cpp \ util/PixmapMerging.cpp \ util/MouseEventFilter.cpp \ util/EventFilter.cpp \ + util/EventReceiver.cpp \ util/Widget.cpp \ util/RsAction.cpp \ util/rsversion.cpp \ diff --git a/retroshare-gui/src/gui/settings/GeneralPage.cpp b/retroshare-gui/src/gui/settings/GeneralPage.cpp index 81300ed86..ffea345d1 100755 --- a/retroshare-gui/src/gui/settings/GeneralPage.cpp +++ b/retroshare-gui/src/gui/settings/GeneralPage.cpp @@ -38,6 +38,7 @@ GeneralPage::GeneralPage(QWidget * parent, Qt::WFlags flags) #ifndef Q_WS_WIN ui.chkRunRetroshareAtSystemStartup->setVisible(false); ui.chkRunRetroshareAtSystemStartupMinimized->setVisible(false); + ui.enableRetroShareProtocol->setVisible(false); #endif } @@ -55,6 +56,10 @@ bool GeneralPage::save(QString &errmsg) #ifdef Q_WS_WIN Settings->setRunRetroshareOnBoot(ui.chkRunRetroshareAtSystemStartup->isChecked(), ui.chkRunRetroshareAtSystemStartupMinimized->isChecked()); + + if (ui.enableRetroShareProtocol->isChecked() != Settings->getRetroShareProtocol()) { + Settings->setRetroShareProtocol(ui.enableRetroShareProtocol->isChecked()); + } #endif Settings->setMaxTimeBeforeIdle(ui.spinBox->value()); @@ -71,6 +76,8 @@ void GeneralPage::load() bool minimized; ui.chkRunRetroshareAtSystemStartup->setChecked(Settings->runRetroshareOnBoot(minimized)); ui.chkRunRetroshareAtSystemStartupMinimized->setChecked(minimized); + + ui.enableRetroShareProtocol->setChecked(Settings->getRetroShareProtocol()); #endif ui.checkStartMinimized->setChecked(Settings->getStartMinimized()); diff --git a/retroshare-gui/src/gui/settings/GeneralPage.ui b/retroshare-gui/src/gui/settings/GeneralPage.ui index 87abfdac9..2d677f9bc 100755 --- a/retroshare-gui/src/gui/settings/GeneralPage.ui +++ b/retroshare-gui/src/gui/settings/GeneralPage.ui @@ -583,6 +583,13 @@ + + + + Register retroshare:// as url protocol (Restart required) + + + diff --git a/retroshare-gui/src/gui/settings/rsharesettings.cpp b/retroshare-gui/src/gui/settings/rsharesettings.cpp index b0131e899..f13f2a182 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.cpp +++ b/retroshare-gui/src/gui/settings/rsharesettings.cpp @@ -37,6 +37,7 @@ #endif // MINIMAL_RSGUI #include +#include #if defined(Q_WS_WIN) #include @@ -472,7 +473,56 @@ RshareSettings::setRunRetroshareOnBoot(bool run, bool minimized) #else /* Platforms othe rthan windows aren't supported yet */ Q_UNUSED(run); - return; + Q_UNUSED(minimized); +#endif +} + +static QString getAppPathForProtocol() +{ + return "\"" + QDir::convertSeparators(QCoreApplication::applicationFilePath()) + "\" -r \"%1\""; +} + +/** Returns true if retroshare:// is registered as protocol */ +bool RshareSettings::getRetroShareProtocol() +{ +#if defined(Q_WS_WIN) + /* Check key */ + QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); + if (retroshare.contains("Default")) { + /* Check profile */ + if (retroshare.value("Profile").toString().toStdString() == rsPeers->getOwnId()) { + /* Check app path */ + QSettings command("HKEY_CLASSES_ROOT\\retroshare\\shell\\open\\command", QSettings::NativeFormat); + if (command.value("Default").toString() == getAppPathForProtocol()) { + return true; + } + } + } +#else + /* Platforms other than windows aren't supported yet */ + return false; +#endif +} + +/** Register retroshare:// as protocl */ +void RshareSettings::setRetroShareProtocol(bool value) +{ +#if defined(Q_WS_WIN) + if (value) { + QSettings retroshare("HKEY_CLASSES_ROOT\\retroshare", QSettings::NativeFormat); + retroshare.setValue("Default", "URL: RetroShare protocol"); + retroshare.setValue("URL Protocol", ""); + retroshare.setValue("Profile", QString::fromStdString(rsPeers->getOwnId())); + + QSettings command("HKEY_CLASSES_ROOT\\retroshare\\shell\\open\\command", QSettings::NativeFormat); + command.setValue("Default", getAppPathForProtocol()); + } else { + QSettings retroshare("HKEY_CLASSES_ROOT", QSettings::NativeFormat); + retroshare.remove("retroshare"); + } +#else + /* Platforms othe rthan windows aren't supported yet */ + Q_UNUSED(value); #endif } diff --git a/retroshare-gui/src/gui/settings/rsharesettings.h b/retroshare-gui/src/gui/settings/rsharesettings.h index be103d4c7..a6bc6393b 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.h +++ b/retroshare-gui/src/gui/settings/rsharesettings.h @@ -109,6 +109,11 @@ public: /** Set whether to run RetroShare on system boot. */ void setRunRetroshareOnBoot(bool run, bool minimized); + /** Returns true if retroshare:// is registered as protocol */ + bool getRetroShareProtocol(); + /** Register retroshare:// as protocl */ + void setRetroShareProtocol(bool value); + /* Get the destination log file. */ QString getLogFile(); /** Set the destination log file. */ diff --git a/retroshare-gui/src/lang/retroshare_de.qm b/retroshare-gui/src/lang/retroshare_de.qm index 2609f8a54..00654f76f 100644 Binary files a/retroshare-gui/src/lang/retroshare_de.qm and b/retroshare-gui/src/lang/retroshare_de.qm differ diff --git a/retroshare-gui/src/lang/retroshare_de.ts b/retroshare-gui/src/lang/retroshare_de.ts index 65d988133..ca36a9cea 100644 --- a/retroshare-gui/src/lang/retroshare_de.ts +++ b/retroshare-gui/src/lang/retroshare_de.ts @@ -4320,12 +4320,12 @@ Gib Dein GPG Passwort wenn Du gefragt wirst ein, um Deinen neuen Schlüssel zu u Nicht in den Systemabschnitt minimieren - + seconds Sekunden - + Start minimized Minimiert starten @@ -4335,7 +4335,12 @@ Gib Dein GPG Passwort wenn Du gefragt wirst ein, um Deinen neuen Schlüssel zu u Starte RetroShare mit dem System - + + Register retroshare:// as url protocol (Restart required) + Registriere retroshare:// als Protokoll (Neustart erforderlich) + + + Idle Untätig @@ -8828,19 +8833,19 @@ p, li { white-space: pre-wrap; } QObject - - + + RetroShare RetroShare - + Inititialize failed. Wrong or missing installation of gpg. Initialisierung fehlgeschlagen. GPG fehlt oder es ist eine falsche Version installiert. - + An unexpected error occured. Please report 'RsInit::InitRetroShare unexpected return code %1'. Ein unerwarteter Fehler ist aufgetreten. Bitte melde 'RsInit::InitRetroShare unexpected return code %1'. @@ -8971,6 +8976,16 @@ Lockdatei: Peer details Nachbar Details + + + No running instance of RetroShare found. + Kein laufendes RetroShare gefunden. + + + + Start with a RetroShare link is only supported for Windows. + Der Start mit einem RetroShare Link wird nur unter Windows unterstützt. + QuickStartWizard @@ -11073,7 +11088,7 @@ p, li { white-space: pre-wrap; } Definiere Farben - + <!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; } diff --git a/retroshare-gui/src/main.cpp b/retroshare-gui/src/main.cpp index 66dd28926..4d1b6f1c5 100644 --- a/retroshare-gui/src/main.cpp +++ b/retroshare-gui/src/main.cpp @@ -42,6 +42,7 @@ #include "gui/connect/ConfCertDialog.h" #include "idle/idle.h" #include "gui/common/Emoticons.h" +#include "util/EventReceiver.h" /*** WINDOWS DON'T LIKE THIS - REDEFINES VER numbers. #include @@ -107,6 +108,14 @@ int main(int argc, char *argv[]) Rshare rshare(args, argc, argv, QString::fromStdString(RsInit::RsConfigDirectory())); + std::string link = RsInit::getRetroShareLink(); + if (!link.empty()) { + /* start with RetroShare link */ + EventReceiver eventReceiver; + eventReceiver.sendRetroShareLink(QString::fromStdString(link)); + return 0; + } + QSplashScreen splashScreen(QPixmap(":/images/splash.png")/* , Qt::WindowStaysOnTopHint*/); switch (initResult) { @@ -229,6 +238,15 @@ int main(int argc, char *argv[]) MainWindow *w = MainWindow::Create (); splashScreen.finish(w); + EventReceiver *eventReceiver = NULL; + if (Settings->getRetroShareProtocol()) { + /* Create event receiver */ + eventReceiver = new EventReceiver; + if (eventReceiver->start()) { + QObject::connect(eventReceiver, SIGNAL(linkReceived(const QUrl&)), w, SLOT(linkActivated(const QUrl&))); + } + } + // I'm using a signal to transfer the hashing info to the mainwindow, because Qt schedules signals properly to // avoid clashes between infos from threads. // @@ -268,7 +286,7 @@ int main(int argc, char *argv[]) w->installGroupChatNotifier(); /* only show window, if not startMinimized */ - if (RsInit::setStartMinimised() || Settings->getStartMinimized()) + if (RsInit::getStartMinimised() || Settings->getStartMinimized()) { splashScreen.close(); } else { @@ -286,6 +304,12 @@ int main(int argc, char *argv[]) #ifndef MINIMAL_RSGUI delete w ; + if (eventReceiver) { + /* Destroy event receiver */ + delete eventReceiver; + eventReceiver = NULL; + } + /* cleanup */ PopupChatDialog::cleanupChat(); #endif // MINIMAL_RSGUI diff --git a/retroshare-gui/src/util/EventReceiver.cpp b/retroshare-gui/src/util/EventReceiver.cpp new file mode 100644 index 000000000..225ca32c5 --- /dev/null +++ b/retroshare-gui/src/util/EventReceiver.cpp @@ -0,0 +1,178 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006, 2007 crypton + * + * 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 "EventReceiver.h" +#include "gui/RetroShareLink.h" + +#ifdef WINDOWS_SYS +#include +#define OP_RETROSHARELINK 12000 +#endif + +struct SharedMemoryInfo +{ +#ifdef WINDOWS_SYS + /* Store handle of the event window */ + WId wid; +#else + long dummy; +#endif +}; + +EventReceiver::EventReceiver() +{ +#ifdef WINDOWS_SYS + setWindowTitle("RetroShare EventReceiver"); +#endif + + /* Build unique name for the running instance */ + QString name = QString("RetroShare-%1::EventReceiver").arg(QCoreApplication::applicationDirPath()); + sharedMMemory.setKey(name); +} + +EventReceiver::~EventReceiver() +{ + sharedMMemory.detach(); +} + +bool EventReceiver::start() +{ + if (!sharedMMemory.create(sizeof(SharedMemoryInfo))) { + std::cerr << "EventReceiver::start() Cannot create shared memory !" << sharedMMemory.errorString().toStdString() << std::endl; + return false; + } + + bool result = true; + + if (sharedMMemory.lock()) { + SharedMemoryInfo *info = (SharedMemoryInfo*) sharedMMemory.data(); + if (info) { +#ifdef WINDOWS_SYS + info->wid = winId(); +#else + info->dummy = 0; +#endif + } else { + result = false; + std::cerr << "EventReceiver::start() Shared memory returns a NULL pointer!" << std::endl; + } + + sharedMMemory.unlock(); + } else { + result = false; + std::cerr << "EventReceiver::start() Cannot lock shared memory !" << std::endl; + } + + return result; +} + +void EventReceiver::showNoRunningInstanceFound() +{ + QMessageBox mb(QMessageBox::Critical, "RetroShare", QObject::tr("No running instance of RetroShare found."), QMessageBox::Ok); + mb.setWindowIcon(QIcon(":/images/rstray3.png")); + mb.exec(); +} + +bool EventReceiver::sendRetroShareLink(const QString& link) +{ + if (!sharedMMemory.attach()) { + /* No running instance found */ + showNoRunningInstanceFound(); + return false; + } + + bool result = true; + + if (sharedMMemory.lock()) { + SharedMemoryInfo *info = (SharedMemoryInfo*) sharedMMemory.data(); + if (info) { +#ifdef WINDOWS_SYS + if (info->wid) { + QByteArray linkData = link.toAscii(); + + COPYDATASTRUCT send; + send.cbData = (link.length() + 1) * sizeof(char); + send.dwData = OP_RETROSHARELINK; + send.lpData = (void*) linkData.constData(); + + SendMessage((HWND) info->wid, WM_COPYDATA, (WPARAM) 0, (LPARAM) (PCOPYDATASTRUCT) &send); + } else { + showNoRunningInstanceFound(); + result = false; + } +#else + QMessageBox mb(QMessageBox::Critical, "RetroShare", QObject::tr("Start with a RetroShare link is only supported for Windows."), QMessageBox::Ok); + mb.setWindowIcon(QIcon(":/images/rstray3.png")); + mb.exec(); + + result = false; +#endif + } else { + result = false; + std::cerr << "EventReceiver::sendRetroShareLink() Cannot lock shared memory !" << std::endl; + } + + sharedMMemory.unlock(); + } else { + result = false; + std::cerr << "EventReceiver::start() Cannot lock shared memory !" << std::endl; + } + + sharedMMemory.detach(); + + return result; +} + +#ifdef WINDOWS_SYS +bool EventReceiver::winEvent(MSG* message, long* result) +{ + if (message->message == WM_COPYDATA ) { + /* Extract the struct from lParam */ + COPYDATASTRUCT *data = (COPYDATASTRUCT*) message->lParam; + + if (data && data->dwData == OP_RETROSHARELINK) { + received(QString::fromAscii((const char*) data->lpData, data->cbData)); + + /* Keep the event from Qt */ + *result = 0; + return true; + } + } + + /* Give the event to Qt */ + return false; +} +#endif + +void EventReceiver::received(const QString &url) +{ + RetroShareLink link(url); + if (link.valid()) { + emit linkReceived(link.toUrl()); + } +} diff --git a/retroshare-gui/src/util/EventReceiver.h b/retroshare-gui/src/util/EventReceiver.h new file mode 100644 index 000000000..410abba7a --- /dev/null +++ b/retroshare-gui/src/util/EventReceiver.h @@ -0,0 +1,61 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006,2007 crypton + * + * 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 _EVENTRECEIVER_H +#define _EVENTRECEIVER_H + +#include +#include + +class QUrl; + +class EventReceiver : public +#ifdef WINDOWS_SYS + QWidget +#else + QObject +#endif +{ + Q_OBJECT + +public: + EventReceiver(); + ~EventReceiver(); + + bool start(); + bool sendRetroShareLink(const QString& link); + +signals: + void linkReceived(const QUrl& url); + +private: + void showNoRunningInstanceFound(); + void received(const QString& url); + +#ifdef WINDOWS_SYS + /* Extend QWidget with a class that will capture the WM_COPYDATA messages */ + bool winEvent (MSG* message, long* result); +#endif // WINDOWS_SYS + + QSharedMemory sharedMMemory; +}; + +#endif