X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Fquassel.h;h=a30ece70365effcc2f51d847575b67b97fc9562e;hp=53d9e0bf9dd97e77222bbcf7e46a205b99ccdab1;hb=HEAD;hpb=ab16c77fe03b73a863d9b52b11919bcbac903f58 diff --git a/src/common/quassel.h b/src/common/quassel.h index 53d9e0bf..a298e326 100644 --- a/src/common/quassel.h +++ b/src/common/quassel.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-2022 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,127 +15,321 @@ * 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., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef QUASSEL_H_ -#define QUASSEL_H_ +#pragma once +#include "common-export.h" + +#include +#include + +#include #include +#include #include +#include #include +#include + +#include "abstractsignalwatcher.h" +#include "singleton.h" -#include "abstractcliparser.h" +class QFile; -class Quassel { - Q_DECLARE_TR_FUNCTIONS(Quassel) +class Logger; + +class COMMON_EXPORT Quassel : public QObject, public Singleton +{ + // TODO Qt5: Use Q_GADGET + Q_OBJECT public: - enum RunMode { - Monolithic, - ClientOnly, - CoreOnly - }; - - struct BuildInfo { - QString fancyVersionString; // clickable rev - QString plainVersionString; // no tag - - QString baseVersion; - QString generatedVersion; - QString commitHash; - uint commitDate; - QString buildDate; - bool isSourceDirty; - uint protocolVersion; - uint clientNeedsProtocol; - uint coreNeedsProtocol; - - QString applicationName; - QString coreApplicationName; - QString clientApplicationName; - QString organizationName; - QString organizationDomain; - }; - - virtual ~Quassel(); - - static void setupBuildInfo(const QString &generated); - static inline const BuildInfo & buildInfo(); - static inline RunMode runMode(); - - static QString configDirPath(); - - //! Returns a list of data directory paths - /** There are several locations for applications to install their data files in. On Unix, - * a common location is /usr/share; others include $PREFIX/share and additional directories - * specified in the env variable XDG_DATA_DIRS. - * \return A list of directory paths to look for data files in - */ - static QStringList dataDirPaths(); - - //! Searches for a data file in the possible data directories - /** Data files can reside in $DATA_DIR/apps/quassel, where $DATA_DIR is one of the directories - * returned by \sa dataDirPaths(). - * \Note With KDE integration enabled, files are searched (only) in KDE's appdata dirs. - * \return The full path to the data file if found; a null QString else - */ - static QString findDataFilePath(const QString &filename); - - static QString translationDirPath(); - - //! Returns a list of directories we look for scripts in - /** We look for a subdirectory named "scripts" in the configdir and in all datadir paths. - * \return A list of directory paths containing executable scripts for /exec - */ - static QStringList scriptDirPaths(); - - static void loadTranslation(const QLocale &locale); - - static inline void setCliParser(AbstractCliParser *cliParser); - static inline AbstractCliParser *cliParser(); - static inline QString optionValue(const QString &option); - static inline bool isOptionSet(const QString &option); - - static const QString &coreDumpFileName(); - - static bool DEBUG; - - static void logFatalMessage(const char *msg); - -protected: - Quassel(); - virtual bool init(); - - inline void setRunMode(RunMode mode); - inline void setDataDirPaths(const QStringList &paths); - QStringList findDataDirPaths() const; + enum RunMode + { + Monolithic, + ClientOnly, + CoreOnly + }; + + struct BuildInfo + { + QString fancyVersionString; // clickable rev + QString plainVersionString; // no tag + + QString baseVersion; + QString generatedVersion; + QString commitHash; + QString commitDate; + + uint protocolVersion; // deprecated + + QString applicationName; + QString coreApplicationName; + QString clientApplicationName; + QString organizationName; + QString organizationDomain; + }; + + /** + * This enum defines the optional features supported by cores/clients prior to version 0.13. + * + * Since the number of features declared this way is limited to 16 (due to the enum not having a defined + * width in cores/clients prior to 0.13), and for more robustness when negotiating features on connect, + * the bitfield-based representation was replaced by a string-based representation in 0.13, support for + * which is indicated by having the ExtendedFeatures flag set. Extended features are defined in the Feature + * enum. + * + * @warning Do not alter this enum; new features must be added (only) to the @a Feature enum. + * + * @sa Feature + */ + enum class LegacyFeature : quint32 + { + SynchronizedMarkerLine = 0x0001, + SaslAuthentication = 0x0002, + SaslExternal = 0x0004, + HideInactiveNetworks = 0x0008, + PasswordChange = 0x0010, + CapNegotiation = 0x0020, + VerifyServerSSL = 0x0040, + CustomRateLimits = 0x0080, + // DccFileTransfer = 0x0100, // never in use + AwayFormatTimestamp = 0x0200, + Authenticators = 0x0400, + BufferActivitySync = 0x0800, + CoreSideHighlights = 0x1000, + SenderPrefixes = 0x2000, + RemoteDisconnect = 0x4000, + ExtendedFeatures = 0x8000, + }; + Q_FLAGS(LegacyFeature) + Q_DECLARE_FLAGS(LegacyFeatures, LegacyFeature) + + /** + * A list of features that are optional in core and/or client, but need runtime checking. + * + * Some features require an uptodate counterpart, but don't justify a protocol break. + * This is what we use this enum for. Add such features to it and check at runtime on the other + * side for their existence. + * + * For feature negotiation, these enum values are serialized as strings, so order does not matter. However, + * do not rename existing enum values to avoid breaking compatibility. + * + * This list should be cleaned up after every protocol break, as we can assume them to be present then. + */ + enum class Feature : uint32_t + { + SynchronizedMarkerLine, + SaslAuthentication, + SaslExternal, + HideInactiveNetworks, + PasswordChange, ///< Remote password change + CapNegotiation, ///< IRCv3 capability negotiation, account tracking + VerifyServerSSL, ///< IRC server SSL validation + CustomRateLimits, ///< IRC server custom message rate limits + AwayFormatTimestamp, ///< Timestamp formatting in away (e.g. %%hh:mm%%) + Authenticators, ///< Whether or not the core supports auth backends + BufferActivitySync, ///< Sync buffer activity status + CoreSideHighlights, ///< Core-Side highlight configuration and matching + SenderPrefixes, ///< Show prefixes for senders in backlog + RemoteDisconnect, ///< Allow this peer to be remotely disconnected + ExtendedFeatures, ///< Extended features + LongTime, ///< Serialize time as 64-bit values + RichMessages, ///< Real Name and Avatar URL in backlog + BacklogFilterType, ///< BacklogManager supports filtering backlog by MessageType + EcdsaCertfpKeys, ///< ECDSA keys for CertFP in identities + LongMessageId, ///< 64-bit IDs for messages + SyncedCoreInfo, ///< CoreInfo dynamically updated using signals + LoadBacklogForwards, ///< Allow loading backlog in ascending order, old to new + SkipIrcCaps, ///< Control what IRCv3 capabilities are skipped during negotiation + }; + Q_ENUMS(Feature) + + class Features; + + Quassel(); + + void init(RunMode runMode); + + /** + * Provides access to the Logger instance. + * + * @returns The Logger instance + */ + Logger* logger() const; + + static void setupBuildInfo(); + static const BuildInfo& buildInfo(); + static RunMode runMode(); + + static QString configDirPath(); + + //! Returns a list of data directory paths + /** There are several locations for applications to install their data files in. On Unix, + * a common location is /usr/share; others include $PREFIX/share and additional directories + * specified in the env variable XDG_DATA_DIRS. + * \return A list of directory paths to look for data files in + */ + static QStringList dataDirPaths(); + + //! Searches for a data file in the possible data directories + /** Data files can reside in $DATA_DIR/apps/quassel, where $DATA_DIR is one of the directories + * returned by \sa dataDirPaths(). + * \Note With KDE integration enabled, files are searched (only) in KDE's appdata dirs. + * \return The full path to the data file if found; a null QString else + */ + static QString findDataFilePath(const QString& filename); + + static QString translationDirPath(); + + //! Returns a list of directories we look for scripts in + /** We look for a subdirectory named "scripts" in the configdir and in all datadir paths. + * \return A list of directory paths containing executable scripts for /exec + */ + static QStringList scriptDirPaths(); + + static void loadTranslation(const QLocale& locale); + + static QString optionValue(const QString& option); + static bool isOptionSet(const QString& option); + + using ReloadHandler = std::function; + + static void registerReloadHandler(ReloadHandler handler); + + using QuitHandler = std::function; + + /** + * Registers a handler that is called when the application is supposed to quit. + * + * @note If multiple handlers are registered, they are processed in order of registration. + * @note If any handler is registered, quit() will not call QCoreApplication::quit(). It relies + * on one of the handlers doing so, instead. + * @param quitHandler Handler to register + */ + static void registerQuitHandler(QuitHandler quitHandler); + + const QString& coreDumpFileName(); + +public slots: + /** + * Requests to quit the application. + * + * Calls any registered quit handlers. If no handlers are registered, calls QCoreApplication::quit(). + */ + void quit(); + +signals: + void messageLogged(const QDateTime& timeStamp, const QString& msg); private: - void registerMetaTypes(); + void registerMetaTypes(); + void setupSignalHandling(); + void setupEnvironment(); + void setupCliParser(); + + /** + * Requests a reload of relevant runtime configuration. + * + * Calls any registered reload handlers, and returns the cumulative result. If no handlers are registered, + * does nothing and returns true. + * + * @returns True if configuration reload successful, otherwise false + */ + bool reloadConfig(); + + void logBacktrace(const QString& filename); - static void handleSignal(int signal); - static void logBacktrace(const QString &filename); +private slots: + void handleSignal(AbstractSignalWatcher::Action action); + +private: + BuildInfo _buildInfo; + RunMode _runMode; + bool _quitting{false}; - static BuildInfo _buildInfo; - static AbstractCliParser *_cliParser; - static RunMode _runMode; - static bool _initialized; + QString _coreDumpFileName; + QString _configDirPath; + QStringList _dataDirPaths; + QString _translationDirPath; - static QString _coreDumpFileName; - static QString _configDirPath; - static QStringList _dataDirPaths; - static QString _translationDirPath; + QCommandLineParser _cliParser; + + Logger* _logger; + AbstractSignalWatcher* _signalWatcher{nullptr}; + + std::vector _reloadHandlers; + std::vector _quitHandlers; }; -const Quassel::BuildInfo & Quassel::buildInfo() { return _buildInfo; } -Quassel::RunMode Quassel::runMode() { return _runMode; } -void Quassel::setRunMode(Quassel::RunMode mode) { _runMode = mode; } -void Quassel::setDataDirPaths(const QStringList &paths) { _dataDirPaths = paths; } +// -------------------------------------------------------------------------------------------------------------------- + +/** + * Class representing a set of supported core/client features. + * + * @sa Quassel::Feature + */ +class COMMON_EXPORT Quassel::Features +{ +public: + /** + * Default constructor. + * + * Creates a Feature instance with all known features (i.e., all values declared in the Quassel::Feature enum) set. + * This is useful for easily creating a Feature instance that represent the current version's capabilities. + */ + Features(); + + /** + * Constructs a Feature instance holding the given list of features. + * + * Both the @a features and the @a legacyFeatures arguments are considered (additively). + * This is useful when receiving a list of features from another peer. + * + * @param features A list of strings matching values in the Quassel::Feature enum. Strings that don't match are + * can be accessed after construction via unknownFeatures(), but are otherwise ignored. + * @param legacyFeatures Holds a bit-wise combination of LegacyFeature flag values, which are each added to the list of + * features represented by this Features instance. + */ + Features(const QStringList& features, LegacyFeatures legacyFeatures); -void Quassel::setCliParser(AbstractCliParser *parser) { _cliParser = parser; } -AbstractCliParser *Quassel::cliParser() { return _cliParser; } -QString Quassel::optionValue(const QString &key) { return cliParser()->value(key); } -bool Quassel::isOptionSet(const QString &key) { return cliParser()->isSet(key); } + /** + * Check if a given feature is marked as enabled in this Features instance. + * + * @param feature The feature to be queried + * @returns Whether the given feature is marked as enabled + */ + bool isEnabled(Feature feature) const; -#endif + /** + * Provides a list of all features marked as either enabled or disabled (as indicated by the @a enabled argument) as strings. + * + * @param enabled Whether to return the enabled or the disabled features + * @return A string list containing all enabled or disabled features + */ + QStringList toStringList(bool enabled = true) const; + + /** + * Provides a list of all enabled legacy features (i.e. features defined prior to v0.13) as bit-wise combination in a + * LegacyFeatures type. + * + * @note Extended features cannot be represented this way, and are thus ignored even if set. + * @return A LegacyFeatures type holding the bit-wise combination of all legacy features enabled in this Features instance + */ + LegacyFeatures toLegacyFeatures() const; + + /** + * Provides the list of strings that could not be mapped to Quassel::Feature enum values on construction. + * + * Useful for debugging/logging purposes. + * + * @returns A list of strings that could not be mapped to the Feature enum on construction of this Features instance, if any + */ + QStringList unknownFeatures() const; + +private: + std::vector _features; + QStringList _unknownFeatures; +};