diff options
| author | Markus Mittendrein <git@maxmitti.tk> | 2014-10-06 15:03:54 +0200 |
|---|---|---|
| committer | Markus Mittendrein <git@maxmitti.tk> | 2014-10-06 15:03:54 +0200 |
| commit | 529f38bd8878b6b1bea2b5457031ce936aab8d80 (patch) | |
| tree | 1193caefcad12f6a36f818048e4547e60add4398 /libcommuni/src/core/ircnetwork.cpp | |
| parent | 3b58b5536935adff242928ed9f30e1c0262fbd7c (diff) | |
| download | manager-529f38bd8878b6b1bea2b5457031ce936aab8d80.tar.gz manager-529f38bd8878b6b1bea2b5457031ce936aab8d80.zip | |
addedd communi
Diffstat (limited to 'libcommuni/src/core/ircnetwork.cpp')
| -rw-r--r-- | libcommuni/src/core/ircnetwork.cpp | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/libcommuni/src/core/ircnetwork.cpp b/libcommuni/src/core/ircnetwork.cpp new file mode 100644 index 0000000..d73a9be --- /dev/null +++ b/libcommuni/src/core/ircnetwork.cpp @@ -0,0 +1,687 @@ +/* + Copyright (C) 2008-2014 The Communi Project + + You may use this file under the terms of BSD license as follows: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "ircnetwork.h" +#include "ircnetwork_p.h" +#include "ircconnection_p.h" +#include "ircprotocol.h" +#include "ircconnection.h" +#include "irccommand.h" +#include <QMetaEnum> +#include <QPointer> + +IRC_BEGIN_NAMESPACE + +/*! + \file ircnetwork.h + \brief \#include <IrcNetwork> + */ + +/*! + \class IrcNetwork ircnetwork.h IrcNetwork + \ingroup core + \brief Provides network information and capability management. + + \section info Network information + + IrcNetwork provides various information about the IRC network of a + \ref IrcConnection::network "connection". This includes the \ref name + "network name", supported \ref channelTypes "channel types", channel + user \ref modes "mode characters" and \ref prefixes "prefix letters", + and various \ref numericLimit "numeric limitations", such as the maximum + nick, channel, topic and message lengths. + + Furthermore, IrcNetwork provides convenient methods for converting channel user + \ref modeToPrefix() "modes to prefixes" and \ref prefixToMode() "vice versa" and + testing whether a target name \ref isChannel() "is a channel". + + \note Most properties have empty values until the network + information has been \ref initialized. + + \section capabilities Capability management + + IrcNetwork also provides means for capability management. It maintais a + list of \ref availableCapabilities "available" and \ref activeCapabilities + "active" capabilities, automatically \ref requestedCapabilities "requests" + desired capabilities, and provides convenient methods for \ref requestCapability() + "manual capability requests". + + \sa IrcConnection::network + */ + +/*! + \fn void IrcNetwork::requestingCapabilities() + + This signal is emitted when capabilities are being requested. + + Normally it is enough to add the desired capabilities to the + list of \ref requestedCapabilities "requested capabilities". + Connect to this signal in order to implement more advanced + capability handling eg. based on which capabilities are \ref + availableCapabilities "available". + + \sa requestedCapabilities, availableCapabilities + */ + +/*! + \enum IrcNetwork::ModeType + This enum describes the channel mode types. + */ + +/*! + \var IrcNetwork::TypeA + \brief Type A modes + + Modes that add or remove an address to or from a list. + These modes always take a parameter when sent by the server to a + client; when sent by a client, they may be specified without a + parameter, which requests the server to display the current + contents of the corresponding list on the channel to the client. + */ + +/*! + \var IrcNetwork::TypeB + \brief Type B modes + + Modes that change a setting on the channel. These modes + always take a parameter. + */ + +/*! + \var IrcNetwork::TypeC + \brief Type C modes + + Modes that change a setting on the channel. These modes + take a parameter only when set; the parameter is absent when the + mode is removed both in the client's and server's MODE command. + */ + +/*! + \var IrcNetwork::TypeD + \brief Type D modes + + Modes that change a setting on the channel. These modes + never take a parameter. + */ + +/*! + \var IrcNetwork::AllTypes + \brief All type modes + */ + +/*! + \enum IrcNetwork::Limit + This enum describes the numeric limit types. + */ + +/*! + \var IrcNetwork::NickLength + \brief The maximum nick name length + */ + +/*! + \var IrcNetwork::ChannelLength + \brief The maximum channel name length + */ + +/*! + \var IrcNetwork::TopicLength + \brief The maximum channel topic length + */ + +/*! + \var IrcNetwork::MessageLength + \brief The maximum message length + */ + +/*! + \var IrcNetwork::KickReasonLength + \brief The maximum kick reason length + */ + +/*! + \var IrcNetwork::AwayReasonLength + \brief The maximum away reason length + */ + +/*! + \var IrcNetwork::ModeCount + \brief The maximum number of channel modes allowed per mode command + */ + +#ifndef IRC_DOXYGEN +IrcNetworkPrivate::IrcNetworkPrivate() : q_ptr(0), initialized(false) +{ +} + +static QHash<QString, int> numericValues(const QString& parameter) +{ + QHash<QString, int> values; + const QStringList keyValues = parameter.split(",", QString::SkipEmptyParts); + foreach (const QString& keyValue, keyValues) + values.insert(keyValue.section(":", 0, 0), keyValue.section(":", 1, 1).toInt()); + return values; +} + +void IrcNetworkPrivate::setInfo(const QHash<QString, QString>& info) +{ + Q_Q(IrcNetwork); + if (info.contains("NETWORK")) + setName(info.value("NETWORK")); + if (info.contains("PREFIX")) { + const QString pfx = info.value("PREFIX"); + setModes(pfx.mid(1, pfx.indexOf(')') - 1).split("", QString::SkipEmptyParts)); + setPrefixes(pfx.mid(pfx.indexOf(')') + 1).split("", QString::SkipEmptyParts)); + } + if (info.contains("CHANTYPES")) + setChannelTypes(info.value("CHANTYPES").split("", QString::SkipEmptyParts)); + + // TODO: + if (info.contains("NICKLEN")) + numericLimits.insert("NICKLEN", info.value("NICKLEN").toInt()); + if (info.contains("CHANNELLEN")) + numericLimits.insert("CHANNELLEN", info.value("CHANNELLEN").toInt()); + if (info.contains("TOPICLEN")) + numericLimits.insert("TOPICLEN", info.value("TOPICLEN").toInt()); + if (info.contains("KICKLEN")) + numericLimits.insert("KICKLEN", info.value("KICKLEN").toInt()); + if (info.contains("AWAYLEN")) + numericLimits.insert("AWAYLEN", info.value("AWAYLEN").toInt()); + if (info.contains("MODES")) + numericLimits.insert("MODES", info.value("MODES").toInt()); + if (info.contains("CHANMODES")) + channelModes = info.value("CHANMODES").split(",", QString::SkipEmptyParts); + if (info.contains("MAXLIST")) + modeLimits = numericValues(info.value("MAXLIST")); + if (info.contains("CHANLIMIT")) + channelLimits = numericValues(info.value("CHANLIMIT")); + if (info.contains("TARGMAX")) + targetLimits = numericValues(info.value("TARGMAX")); + + if (!initialized) { + initialized = true; + emit q->initialized(); + } +} + +void IrcNetworkPrivate::setAvailableCapabilities(const QSet<QString>& capabilities) +{ + Q_Q(IrcNetwork); + if (availableCaps != capabilities) { + availableCaps = capabilities; + emit q->availableCapabilitiesChanged(availableCaps.toList()); + } +} + +void IrcNetworkPrivate::setActiveCapabilities(const QSet<QString>& capabilities) +{ + Q_Q(IrcNetwork); + if (activeCaps != capabilities) { + activeCaps = capabilities; + emit q->activeCapabilitiesChanged(activeCaps.toList()); + } +} + +void IrcNetworkPrivate::setName(const QString& value) +{ + Q_Q(IrcNetwork); + if (name != value) { + name = value; + emit q->nameChanged(value); + } +} + +void IrcNetworkPrivate::setModes(const QStringList& value) +{ + Q_Q(IrcNetwork); + if (modes != value) { + modes = value; + emit q->modesChanged(value); + } +} + +void IrcNetworkPrivate::setPrefixes(const QStringList& value) +{ + Q_Q(IrcNetwork); + if (prefixes != value) { + prefixes = value; + emit q->prefixesChanged(value); + } +} + +void IrcNetworkPrivate::setChannelTypes(const QStringList& value) +{ + Q_Q(IrcNetwork); + if (channelTypes != value) { + channelTypes = value; + emit q->channelTypesChanged(value); + } +} +#endif // IRC_DOXYGEN + +/*! + \internal + Constructs a new network object for IRC \a connection. + */ +IrcNetwork::IrcNetwork(IrcConnection* connection) : QObject(connection), d_ptr(new IrcNetworkPrivate) +{ + Q_D(IrcNetwork); + d->q_ptr = this; + d->connection = connection; +} + +/*! + \internal + Destructs the IRC network. + */ +IrcNetwork::~IrcNetwork() +{ +} + +/*! + \property bool IrcNetwork::initialized + This property holds whether the network information has been initialized. + + Most properties have empty values until the server provides the + relevant network information during the client-server handshake. + + \par Access function: + \li bool <b>isInitialized</b>() const + + \par Notifier signal: + \li void <b>initialized</b>() + */ +bool IrcNetwork::isInitialized() +{ + Q_D(const IrcNetwork); + return d->initialized; +} + +/*! + This property holds the network name. + + \par Access function: + \li QString <b>name</b>() const + + \par Notifier signal: + \li void <b>nameChanged</b>(const QString& name) + */ +QString IrcNetwork::name() const +{ + Q_D(const IrcNetwork); + return d->name; +} + +/*! + This property holds the supported channel user mode letters. + + Examples of typical channel user modes: + Description | Mode | Prefix + -----------------|------------|------- + Channel operator | \b o | @ + Voiced user | \b v | + + + \par Access function: + \li QStringList <b>modes</b>() const + + \par Notifier signal: + \li void <b>modesChanged</b>(const QStringList& modes) + + \sa prefixes, modeToPrefix() + */ +QStringList IrcNetwork::modes() const +{ + Q_D(const IrcNetwork); + return d->modes; +} + +/*! + This property holds the supported channel user mode prefix characters. + + Examples of typical channel user modes: + Description | Mode | Prefix + -----------------|------------|------- + Channel operator | o | \b @ + Voiced user | v | \b + + + \par Access function: + \li QStringList <b>prefixes</b>() const + + \par Notifier signal: + \li void <b>prefixesChanged</b>(const QStringList& prefixes) + + \sa modes, prefixToMode() + */ +QStringList IrcNetwork::prefixes() const +{ + Q_D(const IrcNetwork); + return d->prefixes; +} + +/*! + Converts a channel user mode letter to a prefix character. + + \sa modes, prefixToMode() + */ +QString IrcNetwork::modeToPrefix(const QString& mode) const +{ + Q_D(const IrcNetwork); + return d->prefixes.value(d->modes.indexOf(mode)); +} + +/*! + Converts a channel mode prefix character to a mode letter. + + \sa prefixes, modeToPrefix() + */ +QString IrcNetwork::prefixToMode(const QString& prefix) const +{ + Q_D(const IrcNetwork); + return d->modes.value(d->prefixes.indexOf(prefix)); +} + +/*! + This property holds the supported channel type prefix characters. + + Examples of typical channel types: + Description | Type | Example + -----------------|------|--------- + Normal channel | \# | \#communi + Local channel | & | &foo + + \par Access function: + \li QStringList <b>channelTypes</b>() const + + \par Notifier signal: + \li void <b>channelTypesChanged</b>(const QStringList& types) + */ +QStringList IrcNetwork::channelTypes() const +{ + Q_D(const IrcNetwork); + return d->channelTypes; +} + +/*! + Returns \c true if the \a name is a channel. + + \code + QString name = ...; + if (connection->network()->isChannel(name)) + doSomeChannelAction(name); + \endcode + + \sa channelTypes + */ +bool IrcNetwork::isChannel(const QString& name) const +{ + Q_D(const IrcNetwork); + return !name.isEmpty() && d->channelTypes.contains(name.at(0)); +} + +/*! + Returns the supported channel modes for specified \a types. + + \sa ModeType + */ +QStringList IrcNetwork::channelModes(IrcNetwork::ModeTypes types) const +{ + Q_D(const IrcNetwork); + QStringList modes; + if (types & TypeA) + modes += d->channelModes.value(0).split("", QString::SkipEmptyParts); + if (types & TypeB) + modes += d->channelModes.value(1).split("", QString::SkipEmptyParts); + if (types & TypeC) + modes += d->channelModes.value(2).split("", QString::SkipEmptyParts); + if (types & TypeD) + modes += d->channelModes.value(3).split("", QString::SkipEmptyParts); + return modes; +} + +/*! + Returns a numeric type of \a limit, or \c -1 if the limitation is not known. + + \sa modeLimit(), channelLimit(), targetLimit() + */ +int IrcNetwork::numericLimit(Limit limit) const +{ + Q_D(const IrcNetwork); + QString key; + switch (limit) { + case NickLength: key = QLatin1String("NICKLEN"); break; + case ChannelLength: key = QLatin1String("CHANNELLEN"); break; + case TopicLength: key = QLatin1String("TOPICLEN"); break; + case MessageLength: return 512; // RFC 1459 + case KickReasonLength: key = QLatin1String("KICKLEN"); break; + case AwayReasonLength: key = QLatin1String("AWAYLEN"); break; + case ModeCount: key = QLatin1String("MODES"); break; + } + return d->numericLimits.value(key, -1); +} + +/*! + Returns the limit of entries in the list per \a mode, or \c -1 if the limitation is not known. + + \sa modes() + */ +int IrcNetwork::modeLimit(const QString& mode) const +{ + Q_D(const IrcNetwork); + return d->modeLimits.value(mode); +} + +/*! + Returns the limit for a \a type of channels, or \c -1 if the limitation is not known. + + \sa channelTypes() + */ +int IrcNetwork::channelLimit(const QString& type) const +{ + Q_D(const IrcNetwork); + return d->channelLimits.value(type); +} + +/*! + Returns the limit of targets for a \a command, or \c -1 if the limitation is not known. + */ +int IrcNetwork::targetLimit(const QString& command) const +{ + Q_D(const IrcNetwork); + return d->targetLimits.value(command); +} + +/*! + This property holds the available capabilities. + + \par Access function: + \li QStringList <b>availableCapabilities</b>() const + + \par Notifier signal: + \li void <b>availableCapabilitiesChanged</b>(const QStringList& capabilities) + + \sa requestedCapabilities, activeCapabilities + */ +QStringList IrcNetwork::availableCapabilities() const +{ + Q_D(const IrcNetwork); + return d->availableCaps.toList(); +} + +/*! + This property holds the active capabilities. + + \par Access function: + \li QStringList <b>activeCapabilities</b>() const + + \par Notifier signal: + \li void <b>activeCapabilitiesChanged</b>(const QStringList& capabilities) + + \sa requestedCapabilities, availableCapabilities + */ +QStringList IrcNetwork::activeCapabilities() const +{ + Q_D(const IrcNetwork); + return d->activeCaps.toList(); +} + +/*! + Returns \c true if the \a capability is \b available. + + \sa availableCapabilities + */ +bool IrcNetwork::hasCapability(const QString& capability) const +{ + Q_D(const IrcNetwork); + return d->availableCaps.contains(capability); +} + +/*! + Returns \c true if the \a capability is \b active. + + \sa activeCapabilities + */ +bool IrcNetwork::isCapable(const QString& capability) const +{ + Q_D(const IrcNetwork); + return d->activeCaps.contains(capability); +} + +/*! + Requests the specified \a capability. + + \note The \a capability is NOT added to the list of \ref requestedCapabilities + "requested capabilities" to avoid them "piling up". + */ +bool IrcNetwork::requestCapability(const QString& capability) +{ + Q_D(IrcNetwork); + if (d->connection) + return d->connection->sendCommand(IrcCommand::createCapability(QLatin1String("REQ"), capability)); + return false; +} + +/*! + Requests the specified \a capabilities. + + \note The \a capabilities are NOT added to the list of \ref requestedCapabilities + "requested capabilities" to avoid them "piling up". + */ +bool IrcNetwork::requestCapabilities(const QStringList& capabilities) +{ + Q_D(IrcNetwork); + if (d->connection && d->connection->isActive()) + return d->connection->sendCommand(IrcCommand::createCapability(QLatin1String("REQ"), capabilities)); + return false; +} + +/*! + This property holds the requested capabilities. + + These capabilities are automatically requested during the handshake, + right after requestingCapabilities() has been emitted. + + \par Access functions: + \li QStringList <b>requestedCapabilities</b>() const + \li void <b>setRequestedCapabilities</b>(const QStringList& capabilities) + + \par Notifier signal: + \li void <b>requestedCapabilitiesChanged</b>(const QStringList& capabilities) + + \sa availableCapabilities, activeCapabilities + */ +QStringList IrcNetwork::requestedCapabilities() const +{ + Q_D(const IrcNetwork); + return d->requestedCaps.toList(); +} + +void IrcNetwork::setRequestedCapabilities(const QStringList& capabilities) +{ + Q_D(IrcNetwork); + const QSet<QString> caps = capabilities.toSet(); + if (d->requestedCaps != caps) { + d->requestedCaps = caps; + emit requestedCapabilitiesChanged(caps.toList()); + } +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, IrcNetwork::Limit limit) +{ + const int index = IrcNetwork::staticMetaObject.indexOfEnumerator("Limit"); + QMetaEnum enumerator = IrcNetwork::staticMetaObject.enumerator(index); + const char* key = enumerator.valueToKey(limit); + debug << (key ? key : "Unknown"); + return debug; +} + +QDebug operator<<(QDebug debug, IrcNetwork::ModeType type) +{ + const int index = IrcNetwork::staticMetaObject.indexOfEnumerator("ModeType"); + QMetaEnum enumerator = IrcNetwork::staticMetaObject.enumerator(index); + const char* key = enumerator.valueToKey(type); + debug << (key ? key : "Unknown"); + return debug; +} + +QDebug operator<<(QDebug debug, IrcNetwork::ModeTypes types) +{ + QStringList lst; + if (types == IrcNetwork::AllTypes) { + lst << "AllTypes"; + } else { + if (types & IrcNetwork::TypeA) + lst << "TypeA"; + if (types & IrcNetwork::TypeB) + lst << "TypeB"; + if (types & IrcNetwork::TypeC) + lst << "TypeC"; + if (types & IrcNetwork::TypeD) + lst << "TypeD"; + } + debug.nospace() << '(' << qPrintable(lst.join("|")) << ')'; + return debug; +} + +QDebug operator<<(QDebug debug, const IrcNetwork* network) +{ + if (!network) + return debug << "IrcNetwork(0x0) "; + debug.nospace() << network->metaObject()->className() << '(' << (void*) network; + if (!network->objectName().isEmpty()) + debug.nospace() << ", name=" << qPrintable(network->objectName()); + if (!network->name().isEmpty()) + debug.nospace() << ", network=" << qPrintable(network->name()); + debug.nospace() << ')'; + return debug.space(); +} +#endif // QT_NO_DEBUG_STREAM + +#include "moc_ircnetwork.cpp" + +IRC_END_NAMESPACE |
