improved banning; added [url] and [card] tags for chat

This commit is contained in:
Max-Wilhelm Bruker 2011-06-25 21:21:19 +02:00
parent 4b84168bda
commit 05ebb83ba4
36 changed files with 2501 additions and 2073 deletions

View file

@ -136,6 +136,7 @@ SOURCES += src/abstractcounter.cpp \
src/gamescene.cpp \
src/arrowitem.cpp \
src/arrowtarget.cpp \
src/tab.cpp \
src/tab_server.cpp \
src/tab_room.cpp \
src/tab_message.cpp \

View file

@ -2,34 +2,41 @@
#include <QDateTime>
#include <QTextTable>
#include <QScrollBar>
#include <QMouseEvent>
#include <QDesktopServices>
#include "chatview.h"
ChatView::ChatView(const QString &_ownName, QWidget *parent)
: QTextEdit(parent), ownName(_ownName)
ChatView::ChatView(const QString &_ownName, bool _showTimestamps, QWidget *parent)
: QTextBrowser(parent), ownName(_ownName), showTimestamps(_showTimestamps)
{
setTextInteractionFlags(Qt::TextSelectableByMouse);
setReadOnly(true);
setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
setOpenLinks(false);
connect(this, SIGNAL(anchorClicked(const QUrl &)), this, SLOT(openLink(const QUrl &)));
}
void ChatView::appendMessage(QString sender, const QString &message)
void ChatView::appendMessage(QString sender, QString message)
{
QTextCursor cursor(document()->lastBlock());
cursor.movePosition(QTextCursor::End);
QTextBlockFormat blockFormat;
blockFormat.setBottomMargin(3);
blockFormat.setBottomMargin(2);
cursor.insertBlock(blockFormat);
QTextCharFormat timeFormat;
timeFormat.setForeground(Qt::black);
cursor.setCharFormat(timeFormat);
cursor.insertText(QDateTime::currentDateTime().toString("[hh:mm] "));
if (showTimestamps) {
QTextCharFormat timeFormat;
timeFormat.setForeground(Qt::black);
cursor.setCharFormat(timeFormat);
cursor.insertText(QDateTime::currentDateTime().toString("[hh:mm] "));
}
QTextCharFormat senderFormat;
if (sender == ownName) {
senderFormat.setFontWeight(QFont::Bold);
senderFormat.setForeground(Qt::red);
} else
senderFormat.setForeground(Qt::blue);
senderFormat.setForeground(QColor(0, 0, 254));
cursor.setCharFormat(senderFormat);
if (!sender.isEmpty())
sender.append(": ");
@ -39,7 +46,122 @@ void ChatView::appendMessage(QString sender, const QString &message)
if (sender.isEmpty())
messageFormat.setForeground(Qt::darkGreen);
cursor.setCharFormat(messageFormat);
cursor.insertText(message);
int from = 0, index = 0;
while ((index = message.indexOf('[', from)) != -1) {
cursor.insertText(message.left(index));
message = message.mid(index);
if (message.isEmpty())
break;
if (message.startsWith("[card]")) {
message = message.mid(6);
QTextCharFormat tempFormat = messageFormat;
tempFormat.setForeground(Qt::blue);
cursor.setCharFormat(tempFormat);
int closeTagIndex = message.indexOf("[/card]");
cursor.insertText(message.left(closeTagIndex));
cursor.setCharFormat(messageFormat);
if (closeTagIndex == -1)
message.clear();
else
message = message.mid(closeTagIndex + 7);
} else if (message.startsWith("[url]")) {
message = message.mid(5);
int closeTagIndex = message.indexOf("[/url]");
QString url = message.left(closeTagIndex);
if (!url.startsWith("http://"))
url.prepend("http://");
QTextCharFormat tempFormat = messageFormat;
tempFormat.setForeground(QColor(0, 0, 254));
tempFormat.setAnchor(true);
tempFormat.setAnchorHref(url);
cursor.setCharFormat(tempFormat);
cursor.insertText(url);
cursor.setCharFormat(messageFormat);
if (closeTagIndex == -1)
message.clear();
else
message = message.mid(closeTagIndex + 6);
} else
from = 1;
}
if (!message.isEmpty())
cursor.insertText(message);
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}
void ChatView::enterEvent(QEvent * /*event*/)
{
setMouseTracking(true);
}
void ChatView::leaveEvent(QEvent * /*event*/)
{
setMouseTracking(false);
}
QTextFragment ChatView::getFragmentUnderMouse(const QPoint &pos) const
{
QTextCursor cursor(cursorForPosition(pos));
QTextBlock block(cursor.block());
QTextBlock::iterator it;
for (it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment frag = it.fragment();
if (frag.contains(cursor.position()))
return frag;
}
return QTextFragment();
}
QString ChatView::getCardNameUnderMouse(QTextFragment frag) const
{
if (frag.charFormat().foreground().color() == Qt::blue)
return frag.text();
return QString();
}
QString ChatView::getCardNameUnderMouse(const QPoint &pos) const
{
return getCardNameUnderMouse(getFragmentUnderMouse(pos));
}
void ChatView::mouseMoveEvent(QMouseEvent *event)
{
QTextFragment frag = getFragmentUnderMouse(event->pos());
QString cardName = getCardNameUnderMouse(frag);
if (!cardName.isEmpty()) {
viewport()->setCursor(Qt::PointingHandCursor);
emit cardNameHovered(cardName);
} else if (frag.charFormat().isAnchor())
viewport()->setCursor(Qt::PointingHandCursor);
else
viewport()->setCursor(Qt::IBeamCursor);
QTextBrowser::mouseMoveEvent(event);
}
void ChatView::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::MidButton) {
QString cardName = getCardNameUnderMouse(event->pos());
if (!cardName.isEmpty())
emit showCardInfoPopup(event->globalPos(), cardName);
}
QTextBrowser::mousePressEvent(event);
}
void ChatView::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::MidButton)
emit deleteCardInfoPopup();
QTextBrowser::mouseReleaseEvent(event);
}
void ChatView::openLink(const QUrl &link)
{
QDesktopServices::openUrl(link);
}

View file

@ -1,18 +1,36 @@
#ifndef CHATVIEW_H
#define CHATVIEW_H
#include <QTextEdit>
#include <QTextBrowser>
#include <QTextFragment>
class QTextTable;
class QMouseEvent;
class ChatView : public QTextEdit {
class ChatView : public QTextBrowser {
Q_OBJECT;
private:
QTextTable *table;
QString ownName;
bool showTimestamps;
QTextFragment getFragmentUnderMouse(const QPoint &pos) const;
QString getCardNameUnderMouse(QTextFragment frag) const;
QString getCardNameUnderMouse(const QPoint &pos) const;
private slots:
void openLink(const QUrl &link);
public:
ChatView(const QString &_ownName, QWidget *parent = 0);
void appendMessage(QString sender, const QString &message);
ChatView(const QString &_ownName, bool _showTimestamps, QWidget *parent = 0);
void appendMessage(QString sender, QString message);
protected:
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
signals:
void cardNameHovered(QString cardName);
void showCardInfoPopup(QPoint pos, QString cardName);
void deleteCardInfoPopup();
};
#endif

View file

@ -11,7 +11,7 @@ class LocalServer : public Server
public:
LocalServer(QObject *parent = 0);
~LocalServer();
AuthenticationResult checkUserPassword(const QString & /*user*/, const QString & /*password*/) { return UnknownUser; }
AuthenticationResult checkUserPassword(Server_ProtocolHandler * /*handler*/, const QString & /*user*/, const QString & /*password*/) { return UnknownUser; }
QString getLoginMessage() const { return QString(); }
bool getGameShouldPing() const { return false; }
int getMaxGameInactivityTime() const { return 9999999; }

View file

@ -1,11 +1,9 @@
#include "messagelogwidget.h"
#include "player.h"
#include "cardzone.h"
#include "cardinfowidget.h"
#include "protocol_items.h"
#include "soundengine.h"
#include <QMouseEvent>
#include <QTextBlock>
#include <QScrollBar>
QString MessageLogWidget::sanitizeHtml(QString dirty) const
{
@ -15,6 +13,20 @@ QString MessageLogWidget::sanitizeHtml(QString dirty) const
.replace(">", "&gt;");
}
void MessageLogWidget::myAppend(const QString &message)
{
QTextCursor cursor(document()->lastBlock());
cursor.movePosition(QTextCursor::End);
QTextBlockFormat blockFormat;
blockFormat.setBottomMargin(2);
cursor.insertBlock(blockFormat);
cursor.insertHtml(message);
verticalScrollBar()->setValue(verticalScrollBar()->maximum());
}
bool MessageLogWidget::isFemale(Player *player) const
{
return player->getUserInfo()->getGender() == ServerInfo_User::Female;
@ -22,129 +34,129 @@ bool MessageLogWidget::isFemale(Player *player) const
void MessageLogWidget::logConnecting(QString hostname)
{
append(tr("Connecting to %1...").arg(sanitizeHtml(hostname)));
myAppend(tr("Connecting to %1...").arg(sanitizeHtml(hostname)));
}
void MessageLogWidget::logConnected()
{
append(tr("Connected."));
myAppend(tr("Connected."));
}
void MessageLogWidget::logDisconnected()
{
append(tr("Disconnected from server."));
myAppend(tr("Disconnected from server."));
}
void MessageLogWidget::logSocketError(const QString &errorString)
{
append(sanitizeHtml(errorString));
myAppend(sanitizeHtml(errorString));
}
void MessageLogWidget::logServerError(ResponseCode response)
{
switch (response) {
case RespWrongPassword: append(tr("Invalid password.")); break;
case RespWrongPassword: myAppend(tr("Invalid password.")); break;
default: ;
}
}
void MessageLogWidget::logProtocolVersionMismatch(int clientVersion, int serverVersion)
{
append(tr("Protocol version mismatch. Client: %1, Server: %2").arg(clientVersion).arg(serverVersion));
myAppend(tr("Protocol version mismatch. Client: %1, Server: %2").arg(clientVersion).arg(serverVersion));
}
void MessageLogWidget::logProtocolError()
{
append(tr("Protocol error."));
myAppend(tr("Protocol error."));
}
void MessageLogWidget::logGameJoined(int gameId)
{
append(tr("You have joined game #%1.").arg(gameId));
myAppend(tr("You have joined game #%1.").arg(gameId));
}
void MessageLogWidget::logJoin(Player *player)
{
soundEngine->notification();
append(tr("%1 has joined the game.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 has joined the game.").arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logLeave(Player *player)
{
append(tr("%1 has left the game.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 has left the game.").arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logGameClosed()
{
append(tr("The game has been closed."));
myAppend(tr("The game has been closed."));
}
void MessageLogWidget::logJoinSpectator(QString name)
{
append(tr("%1 is now watching the game.").arg(sanitizeHtml(name)));
myAppend(tr("%1 is now watching the game.").arg(sanitizeHtml(name)));
}
void MessageLogWidget::logLeaveSpectator(QString name)
{
append(tr("%1 is not watching the game any more.").arg(sanitizeHtml(name)));
myAppend(tr("%1 is not watching the game any more.").arg(sanitizeHtml(name)));
}
void MessageLogWidget::logDeckSelect(Player *player, int deckId)
{
if (deckId == -1)
append(tr("%1 has loaded a local deck.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 has loaded a local deck.").arg(sanitizeHtml(player->getName())));
else
append(tr("%1 has loaded deck #%2.").arg(sanitizeHtml(player->getName())).arg(deckId));
myAppend(tr("%1 has loaded deck #%2.").arg(sanitizeHtml(player->getName())).arg(deckId));
}
void MessageLogWidget::logReadyStart(Player *player)
{
append(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logNotReadyStart(Player *player)
{
append(tr("%1 is not ready to start the game any more.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 is not ready to start the game any more.").arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logConcede(Player *player)
{
append(tr("%1 has conceded the game.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 has conceded the game.").arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logGameStart()
{
append(tr("The game has started."));
myAppend(tr("The game has started."));
}
void MessageLogWidget::logConnectionStateChanged(Player *player, bool connectionState)
{
if (connectionState)
append(tr("%1 has restored connection to the game.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 has restored connection to the game.").arg(sanitizeHtml(player->getName())));
else
append(tr("%1 has lost connection to the game.").arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 has lost connection to the game.").arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logSay(Player *player, QString message)
{
append(QString("<b><font color=\"") + (player->getLocal() ? "red" : "#0000fe") + QString("\">%1:</font></b> %2").arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(message)));
appendMessage(player->getName(), message);
}
void MessageLogWidget::logSpectatorSay(QString spectatorName, QString message)
{
append(QString("<font color=\"red\">%1:</font> %2").arg(sanitizeHtml(spectatorName)).arg(sanitizeHtml(message)));
myAppend(QString("<font color=\"red\">%1:</font> %2").arg(sanitizeHtml(spectatorName)).arg(sanitizeHtml(message)));
}
void MessageLogWidget::logShuffle(Player *player, CardZone *zone)
{
soundEngine->shuffle();
if (currentContext != MessageContext_Mulligan)
append(tr("%1 shuffles %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)));
myAppend(tr("%1 shuffles %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)));
}
void MessageLogWidget::logRollDie(Player *player, int sides, int roll)
{
append(tr("%1 rolls a %2 with a %3-sided die.").arg(sanitizeHtml(player->getName())).arg(roll).arg(sides));
myAppend(tr("%1 rolls a %2 with a %3-sided die.").arg(sanitizeHtml(player->getName())).arg(roll).arg(sides));
}
void MessageLogWidget::logDrawCards(Player *player, int number)
@ -153,16 +165,16 @@ void MessageLogWidget::logDrawCards(Player *player, int number)
mulliganPlayer = player;
else {
soundEngine->draw();
append(tr("%1 draws %n card(s).", "", number).arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 draws %n card(s).", "", number).arg(sanitizeHtml(player->getName())));
}
}
void MessageLogWidget::logUndoDraw(Player *player, QString cardName)
{
if (cardName.isEmpty())
append((isFemale(player) ? tr("%1 undoes her last draw.") : tr("%1 undoes his last draw.")).arg(sanitizeHtml(player->getName())));
myAppend((isFemale(player) ? tr("%1 undoes her last draw.") : tr("%1 undoes his last draw.")).arg(sanitizeHtml(player->getName())));
else
append((isFemale(player) ? tr("%1 undoes her last draw (%2).") : tr("%1 undoes his last draw (%2).")).arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))));
myAppend((isFemale(player) ? tr("%1 undoes her last draw (%2).") : tr("%1 undoes his last draw (%2).")).arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))));
}
QPair<QString, QString> MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position) const
@ -227,7 +239,7 @@ void MessageLogWidget::doMoveCard(LogMoveCard &attributes)
cardStr = QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName));
if (attributes.startZone->getPlayer() != attributes.targetZone->getPlayer()) {
append(tr("%1 gives %2 control over %3.").arg(sanitizeHtml(attributes.player->getName())).arg(sanitizeHtml(attributes.targetZone->getPlayer()->getName())).arg(cardStr));
myAppend(tr("%1 gives %2 control over %3.").arg(sanitizeHtml(attributes.player->getName())).arg(sanitizeHtml(attributes.targetZone->getPlayer()->getName())).arg(cardStr));
return;
}
@ -260,7 +272,7 @@ void MessageLogWidget::doMoveCard(LogMoveCard &attributes)
finalStr = tr("%1 plays %2%3.");
}
append(finalStr.arg(sanitizeHtml(attributes.player->getName())).arg(cardStr).arg(fromStr).arg(attributes.newX));
myAppend(finalStr.arg(sanitizeHtml(attributes.player->getName())).arg(cardStr).arg(fromStr).arg(attributes.newX));
}
void MessageLogWidget::logMoveCard(Player *player, CardItem *card, CardZone *startZone, int oldX, CardZone *targetZone, int newX)
@ -280,50 +292,50 @@ void MessageLogWidget::logMulligan(Player *player, int number)
return;
if (number > -1)
append(tr("%1 takes a mulligan to %n.", "", number).arg(sanitizeHtml(player->getName())));
myAppend(tr("%1 takes a mulligan to %n.", "", number).arg(sanitizeHtml(player->getName())));
else
append((isFemale(player) ? tr("%1 draws her initial hand.") : tr("%1 draws his initial hand.")).arg(sanitizeHtml(player->getName())));
myAppend((isFemale(player) ? tr("%1 draws her initial hand.") : tr("%1 draws his initial hand.")).arg(sanitizeHtml(player->getName())));
}
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
{
if (faceDown)
append(tr("%1 flips %2 face-down.").arg(sanitizeHtml(player->getName())).arg(cardName));
myAppend(tr("%1 flips %2 face-down.").arg(sanitizeHtml(player->getName())).arg(cardName));
else
append(tr("%1 flips %2 face-up.").arg(sanitizeHtml(player->getName())).arg(cardName));
myAppend(tr("%1 flips %2 face-up.").arg(sanitizeHtml(player->getName())).arg(cardName));
}
void MessageLogWidget::logDestroyCard(Player *player, QString cardName)
{
append(tr("%1 destroys %2.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))));
myAppend(tr("%1 destroys %2.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))));
}
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
{
append(tr("%1 attaches %2 to %3's %4.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))).arg(sanitizeHtml(targetPlayer->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(targetCardName))));
myAppend(tr("%1 attaches %2 to %3's %4.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))).arg(sanitizeHtml(targetPlayer->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(targetCardName))));
}
void MessageLogWidget::logUnattachCard(Player *player, QString cardName)
{
append(tr("%1 unattaches %2.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))));
myAppend(tr("%1 unattaches %2.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))));
}
void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt)
{
append(tr("%1 creates token: %2%3.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\"><a name=\"foo\">%1</a></font>").arg(sanitizeHtml(cardName))).arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt))));
myAppend(tr("%1 creates token: %2%3.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\"><a name=\"foo\">%1</a></font>").arg(sanitizeHtml(cardName))).arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt))));
}
void MessageLogWidget::logCreateArrow(Player *player, Player *startPlayer, QString startCard, Player *targetPlayer, QString targetCard, bool playerTarget)
{
if (playerTarget)
append(tr("%1 points from %2's %3 to %4.")
myAppend(tr("%1 points from %2's %3 to %4.")
.arg(sanitizeHtml(player->getName()))
.arg(sanitizeHtml(startPlayer->getName()))
.arg(sanitizeHtml(startCard))
.arg(sanitizeHtml(targetPlayer->getName()))
);
else
append(tr("%1 points from %2's %3 to %4's %5.")
myAppend(tr("%1 points from %2's %3 to %4's %5.")
.arg(sanitizeHtml(player->getName()))
.arg(sanitizeHtml(startPlayer->getName()))
.arg(sanitizeHtml(startCard))
@ -349,7 +361,7 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c
default: ;
}
append(finalStr.arg(sanitizeHtml(player->getName())).arg(colorStr).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))).arg(value));
myAppend(finalStr.arg(sanitizeHtml(player->getName())).arg(colorStr).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(cardName))).arg(value));
}
void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped)
@ -367,13 +379,13 @@ void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped)
cardStr = isFemale(player) ? tr("her permanents") : tr("his permanents");
else
cardStr = QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()));
append(tr("%1 %2 %3.").arg(sanitizeHtml(player->getName())).arg(tapped ? tr("taps") : tr("untaps")).arg(cardStr));
myAppend(tr("%1 %2 %3.").arg(sanitizeHtml(player->getName())).arg(tapped ? tr("taps") : tr("untaps")).arg(cardStr));
}
}
void MessageLogWidget::logSetCounter(Player *player, QString counterName, int value, int oldValue)
{
append(tr("%1 sets counter %2 to %3 (%4%5).").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(counterName))).arg(QString("<font color=\"blue\">%1</font>").arg(value)).arg(value > oldValue ? "+" : "").arg(value - oldValue));
myAppend(tr("%1 sets counter %2 to %3 (%4%5).").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(counterName))).arg(QString("<font color=\"blue\">%1</font>").arg(value)).arg(value > oldValue ? "+" : "").arg(value - oldValue));
}
void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap)
@ -383,7 +395,7 @@ void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool do
finalStr = tr("%1 sets %2 to not untap normally.");
else
finalStr = tr("%1 sets %2 to untap normally.");
append(finalStr.arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()))));
myAppend(finalStr.arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()))));
}
void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
@ -391,26 +403,26 @@ void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
if (currentContext == MessageContext_MoveCard)
moveCardPT.insert(card, newPT);
else
append(tr("%1 sets PT of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()))).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(newPT))));
myAppend(tr("%1 sets PT of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()))).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(newPT))));
}
void MessageLogWidget::logSetAnnotation(Player *player, CardItem *card, QString newAnnotation)
{
append(tr("%1 sets annotation of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()))).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(newAnnotation))));
myAppend(tr("%1 sets annotation of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(card->getName()))).arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(newAnnotation))));
}
void MessageLogWidget::logDumpZone(Player *player, CardZone *zone, int numberCards)
{
if (numberCards != -1)
append(tr("%1 is looking at the top %2 cards %3.").arg(sanitizeHtml(player->getName())).arg(numberCards).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseGenitive)));
myAppend(tr("%1 is looking at the top %2 cards %3.").arg(sanitizeHtml(player->getName())).arg(numberCards).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseGenitive)));
else
append(tr("%1 is looking at %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative)));
myAppend(tr("%1 is looking at %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative)));
}
void MessageLogWidget::logStopDumpZone(Player *player, CardZone *zone)
{
QString zoneName = zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative);
append(tr("%1 stops looking at %2.").arg(sanitizeHtml(player->getName())).arg(zoneName));
myAppend(tr("%1 stops looking at %2.").arg(sanitizeHtml(player->getName())).arg(zoneName));
}
void MessageLogWidget::logRevealCards(Player *player, CardZone *zone, int cardId, QString cardName, Player *otherPlayer)
@ -433,28 +445,28 @@ void MessageLogWidget::logRevealCards(Player *player, CardZone *zone, int cardId
if (cardId == -1) {
if (otherPlayer)
append(tr("%1 reveals %2 to %3.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)).arg(sanitizeHtml(otherPlayer->getName())));
myAppend(tr("%1 reveals %2 to %3.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)).arg(sanitizeHtml(otherPlayer->getName())));
else
append(tr("%1 reveals %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)));
myAppend(tr("%1 reveals %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)));
} else if (cardId == -2) {
if (otherPlayer)
append(tr("%1 randomly reveals %2%3 to %4.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName())));
myAppend(tr("%1 randomly reveals %2%3 to %4.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName())));
else
append(tr("%1 randomly reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr));
myAppend(tr("%1 randomly reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr));
} else {
if (otherPlayer)
append(tr("%1 reveals %2%3 to %4.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName())));
myAppend(tr("%1 reveals %2%3 to %4.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName())));
else
append(tr("%1 reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr));
myAppend(tr("%1 reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr));
}
}
void MessageLogWidget::logSetActivePlayer(Player *player)
{
soundEngine->notification();
append(QString());
append("<font color=\"green\"><b>" + tr("It is now %1's turn.").arg(player->getName()) + "</b></font>");
append(QString());
myAppend(QString());
myAppend("<font color=\"green\"><b>" + tr("It is now %1's turn.").arg(player->getName()) + "</b></font>");
myAppend(QString());
}
void MessageLogWidget::logSetActivePhase(int phase)
@ -474,7 +486,7 @@ void MessageLogWidget::logSetActivePhase(int phase)
case 9: phaseName = tr("second main phase"); break;
case 10: phaseName = tr("ending phase"); break;
}
append("<font color=\"green\"><b>" + tr("It is now the %1.").arg(phaseName) + "</b></font>");
myAppend("<font color=\"green\"><b>" + tr("It is now the %1.").arg(phaseName) + "</b></font>");
}
void MessageLogWidget::containerProcessingStarted(GameEventContext *_context)
@ -531,67 +543,7 @@ void MessageLogWidget::connectToPlayer(Player *player)
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *)), this, SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *)));
}
MessageLogWidget::MessageLogWidget(QWidget *parent)
: QTextEdit(parent)
MessageLogWidget::MessageLogWidget(const QString &_ownName, QWidget *parent)
: ChatView(_ownName, false, parent)
{
setReadOnly(true);
}
void MessageLogWidget::enterEvent(QEvent * /*event*/)
{
setMouseTracking(true);
}
void MessageLogWidget::leaveEvent(QEvent * /*event*/)
{
setMouseTracking(false);
}
QString MessageLogWidget::getCardNameUnderMouse(const QPoint &pos) const
{
QTextCursor cursor(cursorForPosition(pos));
QTextBlock block(cursor.block());
QTextBlock::iterator it;
for (it = block.begin(); !(it.atEnd()); ++it) {
QTextFragment frag = it.fragment();
if (!frag.contains(cursor.position()))
continue;
if (frag.charFormat().foreground().color() == Qt::blue)
return frag.text();
break;
}
return QString();
}
void MessageLogWidget::mouseMoveEvent(QMouseEvent *event)
{
QString cardName = getCardNameUnderMouse(event->pos());
if (!cardName.isEmpty()) {
viewport()->setCursor(Qt::PointingHandCursor);
emit cardNameHovered(cardName);
} else
viewport()->setCursor(Qt::IBeamCursor);
QTextEdit::mouseMoveEvent(event);
}
void MessageLogWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::MidButton) {
QString cardName = getCardNameUnderMouse(event->pos());
if (!cardName.isEmpty())
emit showCardInfoPopup(event->globalPos(), cardName);
}
QTextEdit::mousePressEvent(event);
}
void MessageLogWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::MidButton)
emit deleteCardInfoPopup();
QTextEdit::mouseReleaseEvent(event);
}

View file

@ -1,15 +1,13 @@
#ifndef MESSAGELOGWIDGET_H
#define MESSAGELOGWIDGET_H
#include <QTextEdit>
#include "chatview.h"
#include <QAbstractSocket>
#include "translation.h"
#include "protocol_datastructures.h"
class Player;
class CardZone;
class QMouseEvent;
class QEvent;
class CardInfoWidget;
class GameEventContext;
class CardItem;
@ -24,16 +22,15 @@ struct LogMoveCard {
int newX;
};
class MessageLogWidget : public QTextEdit {
class MessageLogWidget : public ChatView {
Q_OBJECT
private:
enum MessageContext { MessageContext_None, MessageContext_MoveCard, MessageContext_Mulligan };
CardInfoWidget *infoWidget;
QString sanitizeHtml(QString dirty) const;
void myAppend(const QString &message);
bool isFemale(Player *player) const;
QPair<QString, QString> getFromStr(CardZone *zone, QString cardName, int position) const;
QString getCardNameUnderMouse(const QPoint &pos) const;
MessageContext currentContext;
QList<LogMoveCard> moveCardQueue;
@ -42,10 +39,6 @@ private:
Player *mulliganPlayer;
int mulliganNumber;
signals:
void cardNameHovered(QString cardName);
void showCardInfoPopup(QPoint pos, QString cardName);
void deleteCardInfoPopup();
public slots:
void logConnecting(QString hostname);
void logConnected();
@ -96,13 +89,7 @@ public slots:
void containerProcessingDone();
public:
void connectToPlayer(Player *player);
MessageLogWidget(QWidget *parent = 0);
protected:
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
MessageLogWidget(const QString &_ownName, QWidget *parent = 0);
};
#endif

30
cockatrice/src/tab.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "tab.h"
#include "cardinfowidget.h"
#include <QDesktopWidget>
#include <QApplication>
Tab::Tab(TabSupervisor *_tabSupervisor, QWidget *parent)
: QWidget(parent), tabMenu(0), tabSupervisor(_tabSupervisor), contentsChanged(false), infoPopup(0)
{
}
void Tab::showCardInfoPopup(const QPoint &pos, const QString &cardName)
{
infoPopup = new CardInfoWidget(CardInfoWidget::ModePopUp, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint);
infoPopup->setAttribute(Qt::WA_TransparentForMouseEvents);
infoPopup->setCard(cardName);
QRect screenRect = qApp->desktop()->screenGeometry(this);
infoPopup->move(
qMax(screenRect.left(), qMin(pos.x() - infoPopup->width() / 2, screenRect.left() + screenRect.width() - infoPopup->width())),
qMax(screenRect.top(), qMin(pos.y() - infoPopup->height() / 2, screenRect.top() + screenRect.height() - infoPopup->height()))
);
infoPopup->show();
}
void Tab::deleteCardInfoPopup()
{
if (infoPopup) {
infoPopup->deleteLater();
infoPopup = 0;
}
}

View file

@ -5,6 +5,7 @@
class QMenu;
class TabSupervisor;
class CardInfoWidget;
class Tab : public QWidget {
Q_OBJECT
@ -13,11 +14,14 @@ signals:
protected:
QMenu *tabMenu;
TabSupervisor *tabSupervisor;
protected slots:
void showCardInfoPopup(const QPoint &pos, const QString &cardName);
void deleteCardInfoPopup();
private:
bool contentsChanged;
CardInfoWidget *infoPopup;
public:
Tab(TabSupervisor *_tabSupervisor, QWidget *parent = 0)
: QWidget(parent), tabMenu(0), tabSupervisor(_tabSupervisor), contentsChanged(false) { }
Tab(TabSupervisor *_tabSupervisor, QWidget *parent = 0);
QMenu *getTabMenu() const { return tabMenu; }
bool getContentsChanged() const { return contentsChanged; }
void setContentsChanged(bool _contentsChanged) { contentsChanged = _contentsChanged; }

View file

@ -5,8 +5,6 @@
#include <QAction>
#include <QMessageBox>
#include <QFileDialog>
#include <QApplication>
#include <QDesktopWidget>
#include "tab_game.h"
#include "cardinfowidget.h"
#include "playerlistwidget.h"
@ -160,8 +158,8 @@ void DeckViewContainer::setDeck(DeckList *deck)
readyStartButton->setEnabled(true);
}
TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming)
: Tab(_tabSupervisor), clients(_clients), gameId(_gameId), gameDescription(_gameDescription), localPlayerId(_localPlayerId), spectator(_spectator), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), started(false), resuming(_resuming), currentPhase(-1), infoPopup(0)
TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, const QString &_userName, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming)
: Tab(_tabSupervisor), clients(_clients), gameId(_gameId), gameDescription(_gameDescription), localPlayerId(_localPlayerId), spectator(_spectator), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), started(false), resuming(_resuming), currentPhase(-1)
{
phasesToolbar = new PhasesToolbar;
phasesToolbar->hide();
@ -178,7 +176,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_client
timeElapsedLabel = new QLabel;
timeElapsedLabel->setAlignment(Qt::AlignCenter);
messageLog = new MessageLogWidget;
messageLog = new MessageLogWidget(_userName);
connect(messageLog, SIGNAL(cardNameHovered(QString)), cardInfo, SLOT(setCard(QString)));
connect(messageLog, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString)));
connect(messageLog, SIGNAL(deleteCardInfoPopup()), this, SLOT(deleteCardInfoPopup()));
@ -779,24 +777,3 @@ Player *TabGame::getActiveLocalPlayer() const
return 0;
}
void TabGame::showCardInfoPopup(const QPoint &pos, const QString &cardName)
{
infoPopup = new CardInfoWidget(CardInfoWidget::ModePopUp, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint);
infoPopup->setAttribute(Qt::WA_TransparentForMouseEvents);
infoPopup->setCard(cardName);
QRect screenRect = qApp->desktop()->screenGeometry(this);
infoPopup->move(
qMax(screenRect.left(), qMin(pos.x() - infoPopup->width() / 2, screenRect.left() + screenRect.width() - infoPopup->width())),
qMax(screenRect.top(), qMin(pos.y() - infoPopup->height() / 2, screenRect.top() + screenRect.height() - infoPopup->height()))
);
infoPopup->show();
}
void TabGame::deleteCardInfoPopup()
{
if (infoPopup) {
infoPopup->deleteLater();
infoPopup = 0;
}
}

View file

@ -100,7 +100,6 @@ private:
int activePlayer;
QSplitter *splitter;
CardInfoWidget *infoPopup;
CardInfoWidget *cardInfo;
PlayerListWidget *playerListWidget;
QLabel *timeElapsedLabel;
@ -147,8 +146,6 @@ signals:
void openMessageDialog(const QString &userName, bool focus);
private slots:
void newCardAdded(AbstractCardItem *card);
void showCardInfoPopup(const QPoint &pos, const QString &cardName);
void deleteCardInfoPopup();
void actConcede();
void actLeaveGame();
@ -158,7 +155,7 @@ private slots:
void actNextPhase();
void actNextTurn();
public:
TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming);
TabGame(TabSupervisor *_tabSupervisor, QList<AbstractClient *> &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, const QString &_userName, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming);
~TabGame();
void retranslateUi();
void closeRequest();

View file

@ -11,7 +11,9 @@
TabMessage::TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, const QString &_ownName, const QString &_userName)
: Tab(_tabSupervisor), client(_client), userName(_userName), userOnline(true)
{
chatView = new ChatView(_ownName);
chatView = new ChatView(_ownName, true);
connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString)));
connect(chatView, SIGNAL(deleteCardInfoPopup()), this, SLOT(deleteCardInfoPopup()));
sayEdit = new QLineEdit;
connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage()));

View file

@ -137,7 +137,9 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q
userList = new UserList(tabSupervisor, client, UserList::RoomList);
connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool)));
chatView = new ChatView(ownName);
chatView = new ChatView(ownName, true);
connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString)));
connect(chatView, SIGNAL(deleteCardInfoPopup()), this, SLOT(deleteCardInfoPopup()));
sayLabel = new QLabel;
sayEdit = new QLineEdit;
sayLabel->setBuddy(sayEdit);

View file

@ -221,7 +221,7 @@ void TabSupervisor::addCloseButtonToTab(Tab *tab, int tabIndex)
void TabSupervisor::gameJoined(Event_GameJoined *event)
{
TabGame *tab = new TabGame(this, QList<AbstractClient *>() << client, event->getGameId(), event->getGameDescription(), event->getPlayerId(), event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming());
TabGame *tab = new TabGame(this, QList<AbstractClient *>() << client, event->getGameId(), event->getGameDescription(), event->getPlayerId(), userName, event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming());
connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *)));
connect(tab, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool)));
int tabIndex = myAddTab(tab);
@ -232,7 +232,7 @@ void TabSupervisor::gameJoined(Event_GameJoined *event)
void TabSupervisor::localGameJoined(Event_GameJoined *event)
{
TabGame *tab = new TabGame(this, localClients, event->getGameId(), event->getGameDescription(), event->getPlayerId(), event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming());
TabGame *tab = new TabGame(this, localClients, event->getGameId(), event->getGameDescription(), event->getPlayerId(), QString(), event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming());
connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *)));
int tabIndex = myAddTab(tab);
addCloseButtonToTab(tab, tabIndex);

View file

@ -10,6 +10,53 @@
#include <QMouseEvent>
#include <QMenu>
#include <QInputDialog>
#include <QLabel>
#include <QSpinBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QHBoxLayout>
BanDialog::BanDialog(QWidget *parent)
: QDialog(parent)
{
QLabel *durationLabel = new QLabel(tr("Please enter the duration of the ban (in minutes).\nEnter 0 for an indefinite ban."));
durationEdit = new QSpinBox;
durationEdit->setMinimum(0);
durationEdit->setValue(5);
QLabel *reasonLabel = new QLabel(tr("Please enter the reason for the ban.\nThis is only saved for moderators and cannot be seen by the banned person."));
reasonEdit = new QPlainTextEdit;
QPushButton *okButton = new QPushButton(tr("&OK"));
okButton->setAutoDefault(true);
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
QPushButton *cancelButton = new QPushButton(tr("&Cancel"));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(durationLabel);
vbox->addWidget(durationEdit);
vbox->addWidget(reasonLabel);
vbox->addWidget(reasonEdit);
vbox->addLayout(buttonLayout);
setLayout(vbox);
setWindowTitle(tr("Ban user from server"));
}
int BanDialog::getMinutes() const
{
return durationEdit->value();
}
QString BanDialog::getReason() const
{
return reasonEdit->toPlainText();
}
UserListItemDelegate::UserListItemDelegate(QObject *const parent)
: QStyledItemDelegate(parent)
@ -215,10 +262,9 @@ void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index)
else if (actionClicked == aRemoveFromIgnoreList)
client->sendCommand(new Command_RemoveFromList("ignore", userName));
else if (actionClicked == aBan) {
bool ok;
int minutes = QInputDialog::getInt(this, tr("Duration"), tr("Please enter the duration of the ban (in minutes).\nEnter 0 for an indefinite ban."), 0, 0, 2147483647, 10, &ok);
if (ok)
client->sendCommand(new Command_BanFromServer(userName, minutes));
BanDialog dlg(this);
if (dlg.exec())
client->sendCommand(new Command_BanFromServer(userName, dlg.getMinutes(), dlg.getReason()));
}
delete menu;

View file

@ -1,6 +1,7 @@
#ifndef USERLIST_H
#define USERLIST_H
#include <QDialog>
#include <QGroupBox>
#include <QTreeWidgetItem>
#include <QStyledItemDelegate>
@ -9,6 +10,19 @@ class QTreeWidget;
class ServerInfo_User;
class AbstractClient;
class TabSupervisor;
class QSpinBox;
class QPlainTextEdit;
class BanDialog : public QDialog {
Q_OBJECT
private:
QSpinBox *durationEdit;
QPlainTextEdit *reasonEdit;
public:
BanDialog(QWidget *parent = 0);
int getMinutes() const;
QString getReason() const;
};
class UserListItemDelegate : public QStyledItemDelegate {
public:

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -484,11 +484,12 @@ Command_ShutdownServer::Command_ShutdownServer(const QString &_reason, int _minu
insertItem(new SerializableItem_String("reason", _reason));
insertItem(new SerializableItem_Int("minutes", _minutes));
}
Command_BanFromServer::Command_BanFromServer(const QString &_userName, int _minutes)
Command_BanFromServer::Command_BanFromServer(const QString &_userName, int _minutes, const QString &_reason)
: ModeratorCommand("ban_from_server")
{
insertItem(new SerializableItem_String("user_name", _userName));
insertItem(new SerializableItem_Int("minutes", _minutes));
insertItem(new SerializableItem_String("reason", _reason));
}
void ProtocolItem::initializeHashAuto()
{

View file

@ -80,4 +80,4 @@
6:mulligan:i,number
7:update_server_message
7:shutdown_server:s,reason:i,minutes
8:ban_from_server:s,user_name:i,minutes
8:ban_from_server:s,user_name:i,minutes:s,reason

View file

@ -735,9 +735,10 @@ public:
class Command_BanFromServer : public ModeratorCommand {
Q_OBJECT
public:
Command_BanFromServer(const QString &_userName = QString(), int _minutes = -1);
Command_BanFromServer(const QString &_userName = QString(), int _minutes = -1, const QString &_reason = QString());
QString getUserName() const { return static_cast<SerializableItem_String *>(itemMap.value("user_name"))->getData(); };
int getMinutes() const { return static_cast<SerializableItem_Int *>(itemMap.value("minutes"))->getData(); };
QString getReason() const { return static_cast<SerializableItem_String *>(itemMap.value("reason"))->getData(); };
static SerializableItem *newItem() { return new Command_BanFromServer; }
int getItemId() const { return ItemId_Command_BanFromServer; }
};

View file

@ -52,7 +52,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
QMutexLocker locker(&serverMutex);
if (name.size() > 35)
name = name.left(35);
AuthenticationResult authState = checkUserPassword(name, password);
AuthenticationResult authState = checkUserPassword(session, name, password);
if (authState == PasswordWrong)
return authState;

View file

@ -43,7 +43,6 @@ public:
virtual QMap<QString, ServerInfo_User *> getBuddyList(const QString &name) = 0;
virtual QMap<QString, ServerInfo_User *> getIgnoreList(const QString &name) = 0;
virtual bool getUserBanned(Server_ProtocolHandler * /*client*/, const QString & /*userName*/) const { return false; }
protected:
void prepareDestroy();
QList<Server_ProtocolHandler *> clients;
@ -51,7 +50,7 @@ protected:
QMap<int, Server_Room *> rooms;
virtual bool userExists(const QString &user) = 0;
virtual AuthenticationResult checkUserPassword(const QString &user, const QString &password) = 0;
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password) = 0;
virtual ServerInfo_User *getUserData(const QString &name) = 0;
int getUsersCount() const;
int getGamesCount() const;

View file

@ -280,8 +280,6 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain
QString userName = cmd->getUsername().simplified();
if (userName.isEmpty() || (userInfo != 0))
return RespContextError;
if (server->getUserBanned(this, userName))
return RespWrongPassword;
authState = server->loginUser(this, userName, cmd->getPassword());
if (authState == PasswordWrong)
return RespWrongPassword;

View file

@ -111,7 +111,6 @@ CREATE TABLE IF NOT EXISTS `cockatrice_users` (
`avatar_bmp` blob NOT NULL,
`registrationDate` datetime NOT NULL,
`active` tinyint(1) NOT NULL,
`banned` tinyint(1) NOT NULL,
`token` char(32) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
@ -149,3 +148,12 @@ CREATE TABLE `cockatrice_buddylist` (
KEY `id_user2` (`id_user2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `cockatrice_bans` (
`id_user` int(7) unsigned zerofill NOT NULL,
`id_admin` int(7) unsigned zerofill NOT NULL,
`time_from` datetime NOT NULL,
`minutes` int(6) NOT NULL,
`reason` text NOT NULL,
KEY `id_user` (`id_user`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View file

@ -169,8 +169,15 @@ bool Servatrice::execSqlQuery(QSqlQuery &query)
return false;
}
AuthenticationResult Servatrice::checkUserPassword(const QString &user, const QString &password)
AuthenticationResult Servatrice::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password)
{
serverMutex.lock();
QHostAddress address = static_cast<ServerSocketInterface *>(handler)->getPeerAddress();
for (int i = 0; i < addressBanList.size(); ++i)
if (address == addressBanList[i].first)
return PasswordWrong;
serverMutex.unlock();
QMutexLocker locker(&dbMutex);
const QString method = settings->value("authentication/method").toString();
if (method == "none")
@ -179,15 +186,15 @@ AuthenticationResult Servatrice::checkUserPassword(const QString &user, const QS
checkSql();
QSqlQuery query;
query.prepare("select banned, password from " + dbPrefix + "_users where name = :name and active = 1");
query.prepare("select a.password, timediff(now(), date_add(b.time_from, interval b.minutes minute)) < 0, b.minutes <=> 0 from " + dbPrefix + "_users a left join " + dbPrefix + "_bans b on b.id_user = a.id and b.time_from = (select max(c.time_from) from " + dbPrefix + "_bans c where c.id_user = a.id) where a.name = :name and a.active = 1");
query.bindValue(":name", user);
if (!execSqlQuery(query))
return PasswordWrong;
if (query.next()) {
if (query.value(0).toInt())
if (query.value(1).toInt() || query.value(2).toInt())
return PasswordWrong;
if (query.value(1).toString() == password)
if (query.value(0).toString() == password)
return PasswordRight;
else
return PasswordWrong;
@ -325,19 +332,6 @@ QMap<QString, ServerInfo_User *> Servatrice::getIgnoreList(const QString &name)
return result;
}
bool Servatrice::getUserBanned(Server_ProtocolHandler *client, const QString &userName) const
{
QMutexLocker locker(&serverMutex);
QHostAddress address = static_cast<ServerSocketInterface *>(client)->getPeerAddress();
for (int i = 0; i < addressBanList.size(); ++i)
if (address == addressBanList[i].first)
return true;
for (int i = 0; i < nameBanList.size(); ++i)
if (userName == nameBanList[i].first)
return true;
return false;
}
void Servatrice::updateBanTimer()
{
QMutexLocker locker(&serverMutex);
@ -346,11 +340,6 @@ void Servatrice::updateBanTimer()
addressBanList.removeAt(i);
else
++i;
for (int i = 0; i < nameBanList.size(); )
if (--(nameBanList[i].second) <= 0)
nameBanList.removeAt(i);
else
++i;
}
void Servatrice::updateLoginMessage()

View file

@ -74,13 +74,11 @@ public:
int getUsersWithAddress(const QHostAddress &address) const;
QMap<QString, ServerInfo_User *> getBuddyList(const QString &name);
QMap<QString, ServerInfo_User *> getIgnoreList(const QString &name);
bool getUserBanned(Server_ProtocolHandler *client, const QString &userName) const;
void addAddressBan(const QHostAddress &address, int minutes) { addressBanList.append(QPair<QHostAddress, int>(address, minutes)); }
void addNameBan(const QString &name, int minutes) { nameBanList.append(QPair<QString, int>(name, minutes)); }
void scheduleShutdown(const QString &reason, int minutes);
protected:
bool userExists(const QString &user);
AuthenticationResult checkUserPassword(const QString &user, const QString &password);
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password);
private:
QTimer *pingClock, *statusUpdateClock, *banTimeoutClock;
QTcpServer *tcpServer;
@ -90,7 +88,6 @@ private:
int serverId;
int uptime;
QList<QPair<QHostAddress, int> > addressBanList;
QList<QPair<QString, int> > nameBanList;
int maxGameInactivityTime, maxPlayerInactivityTime;
int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser;
ServerInfo_User *evalUserQueryResult(const QSqlQuery &query, bool complete);

View file

@ -488,14 +488,14 @@ ResponseCode ServerSocketInterface::cmdBanFromServer(Command_BanFromServer *cmd,
ServerSocketInterface *user = static_cast<ServerSocketInterface *>(server->getUsers().value(userName));
if (user->getUserInfo()->getUserLevel() & ServerInfo_User::IsRegistered) {
// Registered users can be banned by name.
if (minutes == 0) {
QMutexLocker locker(&servatrice->dbMutex);
QSqlQuery query;
query.prepare("update " + servatrice->getDbPrefix() + "_users set banned=1 where name = :name");
query.bindValue(":name", userName);
servatrice->execSqlQuery(query);
} else
servatrice->addNameBan(userName, minutes);
QMutexLocker locker(&servatrice->dbMutex);
QSqlQuery query;
query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (id_user, id_admin, time_from, minutes, reason) values(:id_user, :id_admin, NOW(), :minutes, :reason)");
query.bindValue(":id_user", getUserIdInDB(userName));
query.bindValue(":id_admin", getUserIdInDB(userInfo->getName()));
query.bindValue(":minutes", minutes);
query.bindValue(":reason", cmd->getReason());
servatrice->execSqlQuery(query);
} else {
// Unregistered users must be banned by IP address.
// Indefinite address bans are not reasonable -> default to 30 minutes.