diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index e4d7747d7..b5174aa45 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -38,6 +38,7 @@ target_sources(qbt_app PRIVATE applicationinstancemanager.h cmdoptions.h filelogger.h + legalnotice.h qtlocalpeer/qtlocalpeer.h signalhandler.h upgrade.h @@ -47,6 +48,7 @@ target_sources(qbt_app PRIVATE applicationinstancemanager.cpp cmdoptions.cpp filelogger.cpp + legalnotice.cpp main.cpp qtlocalpeer/qtlocalpeer.cpp signalhandler.cpp diff --git a/src/app/application.cpp b/src/app/application.cpp index c052d0bd5..c7cb2a02c 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -57,7 +57,6 @@ #include #ifdef Q_OS_WIN #include -#include #endif // Q_OS_WIN #ifdef Q_OS_MACOS #include @@ -92,7 +91,6 @@ #include "upgrade.h" #ifndef DISABLE_GUI -#include "gui/guiaddtorrentmanager.h" #include "gui/desktopintegration.h" #include "gui/mainwindow.h" #include "gui/shutdownconfirmdialog.h" @@ -271,17 +269,18 @@ Application::Application(int &argc, char **argv) SettingsStorage::initInstance(); Preferences::initInstance(); - const bool firstTimeUser = !Preferences::instance()->getAcceptedLegal(); - if (!firstTimeUser) + const bool firstTimeUser = SettingsStorage::instance()->isEmpty(); + if (firstTimeUser) + { + setCurrentMigrationVersion(); + handleChangedDefaults(DefaultPreferencesMode::Current); + } + else { if (!upgrade()) throw RuntimeError(u"Failed migration of old settings"_s); // Not translatable. Translation isn't configured yet. handleChangedDefaults(DefaultPreferencesMode::Legacy); } - else - { - handleChangedDefaults(DefaultPreferencesMode::Current); - } initializeTranslation(); diff --git a/src/app/cmdoptions.cpp b/src/app/cmdoptions.cpp index 5b1d957b6..21820c85e 100644 --- a/src/app/cmdoptions.cpp +++ b/src/app/cmdoptions.cpp @@ -302,7 +302,10 @@ namespace }; constexpr const BoolOption SHOW_HELP_OPTION {"help", 'h'}; +#if !defined(Q_OS_WIN) || defined(DISABLE_GUI) constexpr const BoolOption SHOW_VERSION_OPTION {"version", 'v'}; +#endif + constexpr const BoolOption CONFIRM_LEGAL_NOTICE {"confirm-legal-notice"}; #if defined(DISABLE_GUI) && !defined(Q_OS_WIN) constexpr const BoolOption DAEMON_OPTION {"daemon", 'd'}; #else @@ -323,7 +326,8 @@ namespace } QBtCommandLineParameters::QBtCommandLineParameters(const QProcessEnvironment &env) - : relativeFastresumePaths(RELATIVE_FASTRESUME.value(env)) + : confirmLegalNotice(CONFIRM_LEGAL_NOTICE.value(env)) + , relativeFastresumePaths(RELATIVE_FASTRESUME.value(env)) #ifndef DISABLE_GUI , noSplash(NO_SPLASH_OPTION.value(env)) #elif !defined(Q_OS_WIN) @@ -365,6 +369,10 @@ QBtCommandLineParameters parseCommandLine(const QStringList &args) result.showVersion = true; } #endif + else if (arg == CONFIRM_LEGAL_NOTICE) + { + result.confirmLegalNotice = true; + } else if (arg == WEBUI_PORT_OPTION) { result.webUIPort = WEBUI_PORT_OPTION.value(arg); @@ -484,10 +492,11 @@ QString makeUsage(const QString &prgName) + indentation + prgName + u' ' + QCoreApplication::translate("CMD Options", "[options] [( | )...]") + u'\n' + QCoreApplication::translate("CMD Options", "Options:") + u'\n' + + SHOW_HELP_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Display this help message and exit")) + u'\n' #if !defined(Q_OS_WIN) || defined(DISABLE_GUI) + SHOW_VERSION_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Display program version and exit")) + u'\n' #endif - + SHOW_HELP_OPTION.usage() + wrapText(QCoreApplication::translate("CMD Options", "Display this help message and exit")) + u'\n' + + CONFIRM_LEGAL_NOTICE.usage() + wrapText(QCoreApplication::translate("CMD Options", "Confirm the legal notice")) + u'\n' + WEBUI_PORT_OPTION.usage(QCoreApplication::translate("CMD Options", "port")) + wrapText(QCoreApplication::translate("CMD Options", "Change the WebUI port")) + u'\n' diff --git a/src/app/cmdoptions.h b/src/app/cmdoptions.h index 1c133c413..c4b42053f 100644 --- a/src/app/cmdoptions.h +++ b/src/app/cmdoptions.h @@ -44,10 +44,11 @@ class QProcessEnvironment; struct QBtCommandLineParameters { bool showHelp = false; - bool relativeFastresumePaths = false; #if !defined(Q_OS_WIN) || defined(DISABLE_GUI) bool showVersion = false; #endif + bool confirmLegalNotice = false; + bool relativeFastresumePaths = false; #ifndef DISABLE_GUI bool noSplash = false; #elif !defined(Q_OS_WIN) diff --git a/src/app/legalnotice.cpp b/src/app/legalnotice.cpp new file mode 100644 index 000000000..af46ee9e5 --- /dev/null +++ b/src/app/legalnotice.cpp @@ -0,0 +1,77 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2023 Mike Tzou (Chocobo1) + * + * 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. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include "legalnotice.h" + +#ifdef DISABLE_GUI +#include +#endif // DISABLE_GUI + +#include +#include + +#ifndef DISABLE_GUI +#include +#endif // DISABLE_GUI + +#include "base/global.h" + +#ifndef DISABLE_GUI +#include "gui/utils.h" +#endif // DISABLE_GUI + +void showLegalNotice(const bool isInteractive) +{ + const QString noticeTitle = QCoreApplication::translate("LegalNotice", "Legal Notice"); + const QString noticeBody = QCoreApplication::translate("LegalNotice", "qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility."); + const QString noticeEnd = QCoreApplication::translate("LegalNotice", "No further notices will be issued."); + + if (!isInteractive) + { + const QString legalNotice = u"\n*** %1 ***\n"_s.arg(noticeTitle) + + noticeBody + u"\n\n" + + QCoreApplication::translate("LegalNotice", "If you have read the legal notice, you can use command line option `--confirm-legal-notice` to suppress this message."); + printf("%s\n\n", qUtf8Printable(legalNotice)); + return; + } + +#ifdef DISABLE_GUI + const QString legalNotice = u"\n*** %1 ***\n"_s.arg(noticeTitle) + + noticeBody + u"\n\n" + + noticeEnd + u"\n\n" + + QCoreApplication::translate("LegalNotice", "Press 'Enter' key to continue..."); + printf("%s", qUtf8Printable(legalNotice)); + getchar(); +#else // DISABLE_GUI + const QString messageBody = noticeBody + u"\n\n" + noticeEnd; + QMessageBox msgBox {QMessageBox::NoIcon, noticeTitle, messageBody, QMessageBox::Ok}; + msgBox.show(); // Need to be shown first or moveToCenter does not work + msgBox.move(Utils::Gui::screenCenter(&msgBox)); + msgBox.exec(); +#endif // DISABLE_GUI +} diff --git a/src/app/legalnotice.h b/src/app/legalnotice.h new file mode 100644 index 000000000..62d47cd4f --- /dev/null +++ b/src/app/legalnotice.h @@ -0,0 +1,31 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2023 Mike Tzou (Chocobo1) + * + * 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. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#pragma once + +void showLegalNotice(bool isInteractive); diff --git a/src/app/main.cpp b/src/app/main.cpp index 5d2c7d042..066a5c2da 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -55,7 +55,6 @@ #include #include #include -#include #include #include @@ -76,11 +75,12 @@ Q_IMPORT_PLUGIN(QICOPlugin) #include "base/logger.h" #include "base/preferences.h" #include "base/profile.h" +#include "base/settingvalue.h" #include "base/version.h" #include "application.h" #include "cmdoptions.h" +#include "legalnotice.h" #include "signalhandler.h" -#include "upgrade.h" #ifndef DISABLE_GUI #include "gui/utils.h" @@ -89,7 +89,6 @@ Q_IMPORT_PLUGIN(QICOPlugin) using namespace std::chrono_literals; void displayVersion(); -bool userAgreesWithLegalNotice(); void displayBadArgMessage(const QString &message); void displayErrorMessage(const QString &message); @@ -168,28 +167,6 @@ int main(int argc, char *argv[]) .arg(u"-h (or --help)"_s)); } - const bool firstTimeUser = !Preferences::instance()->getAcceptedLegal(); - if (firstTimeUser) - { -#ifndef DISABLE_GUI - if (!userAgreesWithLegalNotice()) - return EXIT_SUCCESS; -#elif defined(Q_OS_WIN) - if (_isatty(_fileno(stdin)) - && _isatty(_fileno(stdout)) - && !userAgreesWithLegalNotice()) - return EXIT_SUCCESS; -#else - if (!params.shouldDaemonize - && isatty(fileno(stdin)) - && isatty(fileno(stdout)) - && !userAgreesWithLegalNotice()) - return EXIT_SUCCESS; -#endif - - setCurrentMigrationVersion(); - } - // Check if qBittorrent is already running if (app->hasAnotherInstance()) { @@ -197,7 +174,14 @@ int main(int argc, char *argv[]) if (params.shouldDaemonize) { throw CommandLineParameterError(QCoreApplication::translate("Main", "You cannot use %1: qBittorrent is already running.") - .arg(u"-d (or --daemon)"_s)); + .arg(u"-d (or --daemon)"_s)); + } + + // print friendly message if there are no other command line args + if (argc == 1) + { + const QString message = QCoreApplication::translate("Main", "Another qBittorrent instance is already running."); + printf("%s\n", qUtf8Printable(message)); } #endif @@ -207,6 +191,26 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; } + CachedSettingValue legalNoticeShown {u"LegalNotice/Accepted"_s, false}; + if (params.confirmLegalNotice) + legalNoticeShown = true; + + if (!legalNoticeShown) + { +#ifndef DISABLE_GUI + const bool isInteractive = true; +#elif defined(Q_OS_WIN) + const bool isInteractive = (_isatty(_fileno(stdin)) != 0) && (_isatty(_fileno(stdout)) != 0); +#else + // when run in daemon mode user can only dismiss the notice with command line option + const bool isInteractive = !params.shouldDaemonize + && ((isatty(fileno(stdin)) != 0) && (isatty(fileno(stdout)) != 0)); +#endif + showLegalNotice(isInteractive); + if (isInteractive) + legalNoticeShown = true; + } + #ifdef Q_OS_MACOS // Since Apple made difficult for users to set PATH, we set here for convenience. // Users are supposed to install Homebrew Python for search function. @@ -294,13 +298,13 @@ void displayBadArgMessage(const QString &message) { const QString help = QCoreApplication::translate("Main", "Run application with -h option to read about command line parameters."); #if defined(Q_OS_WIN) && !defined(DISABLE_GUI) - QMessageBox msgBox(QMessageBox::Critical, QCoreApplication::translate("Main", "Bad command line"), + QMessageBox msgBox(QMessageBox::Critical, QCoreApplication::translate("Main", "Bad command line options"), (message + u'\n' + help), QMessageBox::Ok); msgBox.show(); // Need to be shown or to moveToCenter does not work msgBox.move(Utils::Gui::screenCenter(&msgBox)); msgBox.exec(); #else - const QString errMsg = QCoreApplication::translate("Main", "Bad command line: ") + u'\n' + const QString errMsg = QCoreApplication::translate("Main", "Bad command line options:") + u'\n' + message + u'\n' + help + u'\n'; fprintf(stderr, "%s", qUtf8Printable(errMsg)); @@ -331,45 +335,6 @@ void displayErrorMessage(const QString &message) #endif } -bool userAgreesWithLegalNotice() -{ - Preferences *const pref = Preferences::instance(); - Q_ASSERT(!pref->getAcceptedLegal()); - -#ifdef DISABLE_GUI - const QString eula = u"\n*** %1 ***\n"_s.arg(QCoreApplication::translate("Main", "Legal Notice")) - + QCoreApplication::translate("Main", "qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.") + u"\n\n" - + QCoreApplication::translate("Main", "No further notices will be issued.") + u"\n\n" - + QCoreApplication::translate("Main", "Press %1 key to accept and continue...").arg(u"'y'"_s) + u'\n'; - printf("%s", qUtf8Printable(eula)); - - const char ret = getchar(); // Read pressed key - if ((ret == 'y') || (ret == 'Y')) - { - // Save the answer - pref->setAcceptedLegal(true); - return true; - } -#else - QMessageBox msgBox; - msgBox.setText(QCoreApplication::translate("Main", "qBittorrent is a file sharing program. When you run a torrent, its data will be made available to others by means of upload. Any content you share is your sole responsibility.\n\nNo further notices will be issued.")); - msgBox.setWindowTitle(QCoreApplication::translate("Main", "Legal notice")); - msgBox.addButton(QCoreApplication::translate("Main", "Cancel"), QMessageBox::RejectRole); - const QAbstractButton *agreeButton = msgBox.addButton(QCoreApplication::translate("Main", "I Agree"), QMessageBox::AcceptRole); - msgBox.show(); // Need to be shown or to moveToCenter does not work - msgBox.move(Utils::Gui::screenCenter(&msgBox)); - msgBox.exec(); - if (msgBox.clickedButton() == agreeButton) - { - // Save the answer - pref->setAcceptedLegal(true); - return true; - } -#endif // DISABLE_GUI - - return false; -} - #ifdef Q_OS_UNIX void adjustFileDescriptorLimit() { diff --git a/src/base/preferences.cpp b/src/base/preferences.cpp index 8dd1b4f87..32ddcc0ab 100644 --- a/src/base/preferences.cpp +++ b/src/base/preferences.cpp @@ -1480,19 +1480,6 @@ void Preferences::setDNSLastIP(const QString &ip) setValue(u"DNSUpdater/lastIP"_s, ip); } -bool Preferences::getAcceptedLegal() const -{ - return value(u"LegalNotice/Accepted"_s, false); -} - -void Preferences::setAcceptedLegal(const bool accepted) -{ - if (accepted == getAcceptedLegal()) - return; - - setValue(u"LegalNotice/Accepted"_s, accepted); -} - QByteArray Preferences::getMainGeometry() const { return value(u"MainWindow/geometry"_s); diff --git a/src/base/preferences.h b/src/base/preferences.h index f7af048a8..8d78a6404 100644 --- a/src/base/preferences.h +++ b/src/base/preferences.h @@ -340,8 +340,6 @@ public: void setDNSLastUpd(const QDateTime &date); QString getDNSLastIP() const; void setDNSLastIP(const QString &ip); - bool getAcceptedLegal() const; - void setAcceptedLegal(bool accepted); QByteArray getMainGeometry() const; void setMainGeometry(const QByteArray &geometry); bool isFiltersSidebarVisible() const; diff --git a/src/base/settingsstorage.cpp b/src/base/settingsstorage.cpp index ed8f03b0d..9f19f0891 100644 --- a/src/base/settingsstorage.cpp +++ b/src/base/settingsstorage.cpp @@ -224,3 +224,9 @@ bool SettingsStorage::hasKey(const QString &key) const const QReadLocker locker {&m_lock}; return m_data.contains(key); } + +bool SettingsStorage::isEmpty() const +{ + const QReadLocker locker {&m_lock}; + return m_data.isEmpty(); +} diff --git a/src/base/settingsstorage.h b/src/base/settingsstorage.h index 7abbdae46..9163d605a 100644 --- a/src/base/settingsstorage.h +++ b/src/base/settingsstorage.h @@ -109,6 +109,7 @@ public: void removeValue(const QString &key); bool hasKey(const QString &key) const; + bool isEmpty() const; public slots: bool save();