cmake_policy(SET CMP0043 OLD)
endif()
+# Honor visibility settings for all target types
+if (CMAKE_VERSION VERSION_GREATER 3.3)
+ cmake_policy(SET CMP0063 NEW)
+endif()
+
# Simplify later checks
#####################################################################
PURPOSE "Enable support for the snorenotify framework"
)
endif()
-
+
if (WITH_WEBKIT)
find_package(Qt5WebKit QUIET)
mkdir -Force $env:APPVEYOR_BUILD_FOLDER\work\build\$env:APPVEYOR_PROJECT_NAME
cd $env:APPVEYOR_BUILD_FOLDER\work\build\$env:APPVEYOR_PROJECT_NAME
- LogExec cmake -G"Ninja" $env:APPVEYOR_BUILD_FOLDER -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_ROOT" -DUSE_QT5=ON -DCMAKE_DISABLE_FIND_PACKAGE_Qt5DBus=ON -DWITH_WEBKIT=OFF
+ LogExec cmake -G"Ninja" $env:APPVEYOR_BUILD_FOLDER -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$CMAKE_INSTALL_ROOT" -DUSE_QT5=ON -DCMAKE_DISABLE_FIND_PACKAGE_Qt5DBus=ON -DWITH_WEBKIT=ON
CmakeImageInstall
$imageDir = CreateDeployImage @(
"bin\\Qt5Opengl\.dll",
"bin\\Qt5Multimedia\.dll",
"bin\\Qt5MultimediaWidgets\.dll",
+ "bin\\Qt5Positioning\.dll",
+ "bin\\Qt5PrintSupport\.dll",
"bin\\Qt5Qml\.dll",
"bin\\Qt5Quick\.dll",
"bin\\Qt5Script\.dll",
+ "bin\\Qt5Sensors\.dll",
"bin\\Qt5Sql\.dll",
+ "bin\\Qt5WebChannel\.dll",
+ "bin\\Qt5WebKit\.dll",
+ "bin\\Qt5WebKitWidgets\.dll",
"bin\\Qt5Widgets\.dll",
"bin\\Qt5XmlPatterns\.dll",
"bin\\.*libglesv2\.dll",
Comment[sq]=një mesazh privat (kërkesë) ka mbërritur
Comment[tr]=Bir özel mesaj (sorgusu) ulaştı
Comment[uk]=Надійшло особисте повідомлення (повідомлення діалогу)
-Comment[zh_CN]=收到一条死人短信息(疑问)
+Comment[zh_CN]=收到一条私人短信息(询问)
Sound=KDE-Im-Message-In.ogg
Action=Sound|Popup|Taskbar
Comment[pt_BR]=Uma mensagem privada (consulta) chegou enquanto o Quassel está focado
Comment[sq]=Një masazh privat (kërkesë) ka mbërritur kur Quassel ishte i fokusuar
Comment[uk]=Під час перебування Quassel у фокусі надійшло особисте повідомлення (повідомлення з діалогу)
-Comment[zh_CN]=当Quassel被聚焦时,收到一条私人短信息(疑问)
+Comment[zh_CN]=当Quassel被聚焦时,收到一条私人短信息(询问)
Sound=KDE-Im-Message-In.ogg
Action=Taskbar
: Transfer(uuid, parent),
_file(0)
{
- connect(this, SIGNAL(stateChanged(Transfer::State)), SLOT(onStateChanged(Transfer::State)));
+ connect(this, SIGNAL(statusChanged(Transfer::Status)), SLOT(onStatusChanged(Transfer::Status)));
+}
+
+
+quint64 ClientTransfer::transferred() const
+{
+ if (status() == Status::Completed)
+ return fileSize();
+
+ return _file ? _file->size() : 0;
}
qWarning() << Q_FUNC_INFO << "Could not write to file:" << _file->errorString();
return;
}
+
+ emit transferredChanged(transferred());
}
-void ClientTransfer::onStateChanged(Transfer::State state)
+void ClientTransfer::onStatusChanged(Transfer::Status status)
{
- switch(state) {
- case State::Completed:
+ switch(status) {
+ case Status::Completed:
if (_file)
_file->close();
break;
- case State::Failed:
+ case Status::Failed:
if (_file)
_file->remove();
break;
QString savePath() const;
+ quint64 transferred() const override;
+
public slots:
// called on the client side
- void accept(const QString &savePath) const;
- void reject() const;
+ void accept(const QString &savePath) const override;
+ void reject() const override;
private slots:
- void dataReceived(PeerPtr peer, const QByteArray &data);
- void onStateChanged(Transfer::State state);
+ void dataReceived(PeerPtr peer, const QByteArray &data) override;
+ void onStatusChanged(Transfer::Status status);
private:
- virtual void cleanUp();
+ void cleanUp() override;
mutable QString _savePath;
QString msg = msg_;
// leading slashes indicate there's a command to call unless there is another one in the first section (like a path /proc/cpuinfo)
+ // For those habitally tied to irssi, "/ " also makes the rest of the line a literal message
int secondSlashPos = msg.indexOf('/', 1);
int firstSpacePos = msg.indexOf(' ');
- if (!msg.startsWith('/') || (secondSlashPos != -1 && (secondSlashPos < firstSpacePos || firstSpacePos == -1))) {
+ if (!msg.startsWith('/') || firstSpacePos == 1 || (secondSlashPos != -1 && (secondSlashPos < firstSpacePos || firstSpacePos == -1))) {
if (msg.startsWith("//"))
- msg.remove(0, 1); // //asdf is transformed to /asdf
+ msg.remove(0, 1); // "//asdf" is transformed to "/asdf"
+ else if (msg.startsWith("/ "))
+ msg.remove(0, 2); // "/ /asdf" is transformed to "/asdf"
msg.prepend("/SAY "); // make sure we only send proper commands to the core
}
else {
Highlight = 0x02,
Redirected = 0x04,
ServerMsg = 0x08,
+ StatusMsg = 0x10,
Backlog = 0x80
};
Q_DECLARE_FLAGS(Flags, Flag)
}
+bool Network::isStatusMsg(const QString &target) const
+{
+ if (target.isEmpty())
+ return false;
+
+ if (supports("STATUSMSG"))
+ return support("STATUSMSG").contains(target[0]);
+ else
+ return QString("@+").contains(target[0]);
+}
+
+
NetworkInfo Network::networkInfo() const
{
NetworkInfo info;
bool isChannelName(const QString &channelname) const;
+ /**
+ * Checks if the target counts as a STATUSMSG
+ *
+ * Status messages are prefixed with one or more characters from the server-provided STATUSMSG
+ * if available, otherwise "@" and "+" are assumed. Generally, status messages sent to a
+ * channel are only visible to those with the same or higher permissions, e.g. voiced.
+ *
+ * @param[in] target Name of destination, e.g. a channel or query
+ * @returns True if a STATUSMSG, otherwise false
+ */
+ bool isStatusMsg(const QString &target) const;
+
inline bool isConnected() const { return _connected; }
//Network::ConnectionState connectionState() const;
inline int connectionState() const { return _connectionState; }
INIT_SYNCABLE_OBJECT(Transfer)
Transfer::Transfer(const QUuid &uuid, QObject *parent)
: SyncableObject(parent),
- _state(State::New),
+ _status(Status::New),
_direction(Direction::Receive),
_port(0),
_fileSize(0),
Transfer::Transfer(Direction direction, const QString &nick, const QString &fileName, const QHostAddress &address, quint16 port, quint64 fileSize, QObject *parent)
: SyncableObject(parent),
- _state(State::New),
+ _status(Status::New),
_direction(direction),
_fileName(fileName),
_address(address),
void Transfer::init()
{
static auto regTypes = []() -> bool {
- qRegisterMetaType<State>("Transfer::State");
+ qRegisterMetaType<Status>("Transfer::Status");
qRegisterMetaType<Direction>("Transfer::Direction");
- qRegisterMetaTypeStreamOperators<State>("Transfer::State");
+ qRegisterMetaTypeStreamOperators<Status>("Transfer::Status");
qRegisterMetaTypeStreamOperators<Direction>("Transfer::Direction");
return true;
}();
}
-Transfer::State Transfer::state() const
+Transfer::Status Transfer::status() const
{
- return _state;
+ return _status;
}
-void Transfer::setState(Transfer::State state)
+void Transfer::setStatus(Transfer::Status status)
{
- if (_state != state) {
- _state = state;
- SYNC(ARG(state));
- emit stateChanged(state);
+ if (_status != status) {
+ _status = status;
+ SYNC(ARG(status));
+ emit statusChanged(status);
}
}
+QString Transfer::prettyStatus() const
+{
+ switch(status()) {
+ case Status::New:
+ return tr("New");
+ case Status::Pending:
+ return tr("Pending");
+ case Status::Connecting:
+ return tr("Connecting");
+ case Status::Transferring:
+ return tr("Transferring");
+ case Status::Paused:
+ return tr("Paused");
+ case Status::Completed:
+ return tr("Completed");
+ case Status::Failed:
+ return tr("Failed");
+ case Status::Rejected:
+ return tr("Rejected");
+ }
+
+ return QString();
+}
+
+
Transfer::Direction Transfer::direction() const
{
{
qWarning() << Q_FUNC_INFO << errorString;
emit error(errorString);
- setState(State::Failed);
+ setStatus(Status::Failed);
cleanUp();
}
-QDataStream &operator<<(QDataStream &out, Transfer::State state) {
+QDataStream &operator<<(QDataStream &out, Transfer::Status state) {
out << static_cast<qint8>(state);
return out;
}
-QDataStream &operator>>(QDataStream &in, Transfer::State &state) {
+QDataStream &operator>>(QDataStream &in, Transfer::Status &state) {
qint8 s;
in >> s;
- state = static_cast<Transfer::State>(s);
+ state = static_cast<Transfer::Status>(s);
return in;
}
SYNCABLE_OBJECT
Q_PROPERTY(QUuid uuid READ uuid);
- Q_PROPERTY(Transfer::State state READ state WRITE setState NOTIFY stateChanged);
+ Q_PROPERTY(Transfer::Status status READ status WRITE setStatus NOTIFY statusChanged);
Q_PROPERTY(Transfer::Direction direction READ direction WRITE setDirection NOTIFY directionChanged);
Q_PROPERTY(QHostAddress address READ address WRITE setAddress NOTIFY addressChanged);
Q_PROPERTY(quint16 port READ port WRITE setPort NOTIFY portChanged);
Q_PROPERTY(QString nick READ nick WRITE setNick NOTIFY nickChanged);
public:
- enum class State {
+ enum class Status {
New,
Pending,
Connecting,
Transfer(const QUuid &uuid, QObject *parent = 0); // for creating a syncable object client-side
Transfer(Direction direction, const QString &nick, const QString &fileName, const QHostAddress &address, quint16 port, quint64 size = 0, QObject *parent = 0);
- inline virtual const QMetaObject *syncMetaObject() const { return &staticMetaObject; }
+ inline const QMetaObject *syncMetaObject() const override { return &staticMetaObject; }
QUuid uuid() const;
- State state() const;
+ Status status() const;
+ QString prettyStatus() const;
Direction direction() const;
QString fileName() const;
QHostAddress address() const;
quint64 fileSize() const;
QString nick() const;
+ virtual quint64 transferred() const = 0;
+
public slots:
// called on the client side
virtual void accept(const QString &savePath) const { Q_UNUSED(savePath); }
virtual void requestRejected(PeerPtr peer) { Q_UNUSED(peer); }
signals:
- void stateChanged(Transfer::State state);
+ void statusChanged(Transfer::Status state);
void directionChanged(Transfer::Direction direction);
void addressChanged(const QHostAddress &address);
void portChanged(quint16 port);
void fileNameChanged(const QString &fileName);
void fileSizeChanged(quint64 fileSize);
+ void transferredChanged(quint64 transferred);
void nickChanged(const QString &nick);
void error(const QString &errorString);
void rejected(PeerPtr peer = 0) const;
protected slots:
- void setState(Transfer::State state);
+ void setStatus(Transfer::Status status);
void setError(const QString &errorString);
// called on the client side through sync calls
void setNick(const QString &nick);
- State _state;
+ Status _status;
Direction _direction;
QString _fileName;
QHostAddress _address;
QUuid _uuid;
};
-Q_DECLARE_METATYPE(Transfer::State)
+Q_DECLARE_METATYPE(Transfer::Status)
Q_DECLARE_METATYPE(Transfer::Direction)
-QDataStream &operator<<(QDataStream &out, Transfer::State state);
-QDataStream &operator>>(QDataStream &in, Transfer::State &state);
+QDataStream &operator<<(QDataStream &out, Transfer::Status state);
+QDataStream &operator>>(QDataStream &in, Transfer::Status &state);
QDataStream &operator<<(QDataStream &out, Transfer::Direction direction);
QDataStream &operator>>(QDataStream &in, Transfer::Direction &direction);
}
+quint64 CoreTransfer::transferred() const
+{
+ return _pos;
+}
+
+
void CoreTransfer::cleanUp()
{
if (_socket) {
void CoreTransfer::onSocketDisconnected()
{
- if (state() == State::Connecting || state() == State::Transferring) {
+ if (status() == Status::Connecting || status() == Status::Transferring) {
setError(tr("Socket closed while still transferring!"));
}
else
{
Q_UNUSED(error)
- if (state() == State::Connecting || state() == State::Transferring) {
+ if (status() == Status::Connecting || status() == Status::Transferring) {
setError(tr("DCC connection error: %1").arg(_socket->errorString()));
}
}
void CoreTransfer::requestAccepted(PeerPtr peer)
{
- if (_peer || !peer || state() != State::New)
+ if (_peer || !peer || status() != Status::New)
return; // transfer was already accepted
_peer = peer;
- setState(State::Pending);
+ setStatus(Status::Pending);
emit accepted(peer);
void CoreTransfer::requestRejected(PeerPtr peer)
{
- if (_peer || state() != State::New)
+ if (_peer || status() != Status::New)
return;
_peer = peer;
- setState(State::Rejected);
+ setStatus(Status::Rejected);
emit rejected(peer);
}
void CoreTransfer::start()
{
- if (!_peer || state() != State::Pending || direction() != Direction::Receive)
+ if (!_peer || status() != Status::Pending || direction() != Direction::Receive)
return;
setupConnectionForReceive();
return;
}
- setState(State::Connecting);
+ setStatus(Status::Connecting);
_socket = new QTcpSocket(this);
connect(_socket, SIGNAL(connected()), SLOT(startReceiving()));
void CoreTransfer::startReceiving()
{
- setState(State::Transferring);
+ setStatus(Status::Transferring);
}
while (_socket->bytesAvailable()) {
QByteArray data = _socket->read(chunkSize);
_pos += data.size();
+ emit transferredChanged(transferred());
if (!relayData(data, true))
return;
else if (_pos == fileSize()) {
qDebug() << "DCC Receive: Transfer finished";
if (relayData(QByteArray(), false)) // empty buffer
- setState(State::Completed);
+ setStatus(Status::Completed);
}
_reading = false;
public:
CoreTransfer(Direction direction, const QString &nick, const QString &fileName, const QHostAddress &address, quint16 port, quint64 size = 0, QObject *parent = 0);
+ quint64 transferred() const override;
+
public slots:
void start();
// called through sync calls
- void requestAccepted(PeerPtr peer);
- void requestRejected(PeerPtr peer);
+ void requestAccepted(PeerPtr peer) override;
+ void requestRejected(PeerPtr peer) override;
private slots:
void startReceiving();
private:
void setupConnectionForReceive();
bool relayData(const QByteArray &data, bool requireChunkSize);
- virtual void cleanUp();
+ void cleanUp() override;
QPointer<Peer> _peer;
QTcpSocket *_socket;
? Message::Redirected
: Message::None;
+ bool isStatusMsg = false;
+
+ // First remove all statusmsg prefix characters that are not also channel prefix characters.
+ while (e->network()->isStatusMsg(e->target()) && !e->network()->isChannelName(e->target())) {
+ isStatusMsg = true;
+ e->setTarget(e->target().remove(0, 1));
+ }
+
+ // Then continue removing statusmsg characters as long as removing the character will still result in a
+ // valid channel name. This prevents removing the channel prefix character if said character is in the
+ // overlap between the statusmsg characters and the channel prefix characters.
+ while (e->network()->isStatusMsg(e->target()) && e->network()->isChannelName(e->target().remove(0, 1))) {
+ isStatusMsg = true;
+ e->setTarget(e->target().remove(0, 1));
+ }
+
+ // If any statusmsg characters were removed, Flag the message as a StatusMsg.
+ if (isStatusMsg) {
+ flags |= Message::StatusMsg;
+ }
+
if (coreSession()->networkConfig()->standardCtcp())
parseStandard(e, messagetype, dequotedMessage, ctcptype, flags);
else
QStringList targets = net->serverDecode(params.at(0)).split(',', QString::SkipEmptyParts);
QStringList::const_iterator targetIter;
for (targetIter = targets.constBegin(); targetIter != targets.constEnd(); ++targetIter) {
- QString target = net->isChannelName(*targetIter) ? *targetIter : senderNick;
+ QString target = net->isChannelName(*targetIter) || net->isStatusMsg(*targetIter) ? *targetIter : senderNick;
msg = decrypt(net, target, msg);
void nickSelectionChanged(const QModelIndexList &);
protected:
- virtual QSize sizeHint() const;
- virtual void hideEvent(QHideEvent *);
- virtual void showEvent(QShowEvent *);
+ QSize sizeHint() const override;
+ void hideEvent(QHideEvent *) override;
+ void showEvent(QShowEvent *) override;
protected slots:
- virtual void currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
- virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override;
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
private slots:
void removeBuffer(BufferId bufferId);
<item>
<widget class="QLabel" name="label">
<property name="toolTip">
- <string>amount of messages per buffer that are requested after the core connection has been established.</string>
+ <string>Amount of messages per buffer that are requested after the core connection has been established.</string>
</property>
<property name="text">
<string>Initial backlog amount:</string>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
- <string>Web Search Url:</string>
+ <string>Web Search URL:</string>
</property>
</widget>
</item>
<widget class="QComboBox" name="proxyType">
<item>
<property name="text">
- <string>Socks 5</string>
+ <string>SOCKS 5</string>
</property>
</item>
<item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="toolTip">
- <string>Incoming messages encoded in Utf8 will always be treated as such.
-This setting defines the encoding for messages that are not Utf8.</string>
+ <string>Incoming messages encoded in UTF-8 will always be treated as such.
+This setting defines the encoding for messages that are not UTF-8.</string>
</property>
<property name="text">
<string>Receive fallback:</string>
</sizepolicy>
</property>
<property name="toolTip">
- <string>Incoming messages encoded in Utf8 will always be treated as such.
-This setting defines the encoding for messages that are not Utf8.</string>
+ <string>Incoming messages encoded in UTF-8 will always be treated as such.
+This setting defines the encoding for messages that are not UTF-8.</string>
</property>
<property name="insertPolicy">
<enum>QComboBox::InsertAlphabetically</enum>
<widget class="QComboBox" name="proxyType">
<item>
<property name="text">
- <string>Socks 5</string>
+ <string>SOCKS 5</string>
</property>
</item>
<item>