File indexing completed on 2023-12-03 11:03:42

0001 // Copyright (c) 2002-2004 Rob Kaper <cap@capsi.com>
0002 //
0003 // This library is free software; you can redistribute it and/or
0004 // modify it under the terms of the GNU Lesser General Public
0005 // License version 2.1 as published by the Free Software Foundation.
0006 //
0007 // This library is distributed in the hope that it will be useful,
0008 // but WITHOUT ANY WARRANTY; without even the implied warranty of
0009 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0010 // Lesser General Public License for more details.
0011 //
0012 // You should have received a copy of the GNU Lesser General Public License
0013 // along with this library; see the file COPYING.LIB.  If not, write to
0014 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0015 // Boston, MA 02110-1301, USA.
0016 
0017 #include <iostream>
0018 
0019 #include <qtextcodec.h>
0020 #include <QTimer>
0021 #include <QTcpSocket>
0022 #include <QHostAddress>
0023 
0024 #include <klocalizedstring.h>
0025 
0026 #include <atlantic_core.h>
0027 #include <auction.h>
0028 #include <card.h>
0029 #include <configoption.h>
0030 #include <estate.h>
0031 #include <estategroup.h>
0032 #include <game.h>
0033 #include <player.h>
0034 #include <trade.h>
0035 
0036 #include "atlantik_network.h"
0037 
0038 #include <libatlantikclient_debug.h>
0039 
0040 AtlantikNetwork::AtlantikNetwork(AtlanticCore *atlanticCore)
0041     : QObject()
0042     , m_atlanticCore(atlanticCore)
0043     , m_monopdsocket(nullptr)
0044     , m_playerId(-1)
0045 {
0046     reset();
0047 }
0048 
0049 AtlantikNetwork::~AtlantikNetwork(void)
0050 {
0051     disconnect();
0052 }
0053 
0054 void AtlantikNetwork::disconnect()
0055 {
0056     if (m_monopdsocket) {
0057         m_monopdstream.setDevice(nullptr);
0058         m_monopdsocket->close();
0059         delete m_monopdsocket;
0060         m_monopdsocket = nullptr;
0061     }
0062 }
0063 
0064 void AtlantikNetwork::reset()
0065 {
0066     disconnect();
0067     m_monopdsocket = new QTcpSocket(this);
0068     m_monopdsocket->setSocketOption(QAbstractSocket::LowDelayOption, true);
0069 
0070     connect(m_monopdsocket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)), this, SLOT(slotConnectionFailed(QAbstractSocket::SocketError)));
0071     connect(m_monopdsocket, SIGNAL(connected()), this, SLOT(slotConnectionSuccess()));
0072     connect(m_monopdsocket, SIGNAL(hostFound()), this, SLOT(slotLookupFinished()));
0073     connect(m_monopdsocket, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
0074 }
0075 
0076 QString AtlantikNetwork::host() const
0077 {
0078     return isConnected()
0079       ? m_monopdsocket->peerAddress().toString()
0080       : QString();
0081 }
0082 
0083 int AtlantikNetwork::port() const
0084 {
0085     return isConnected()
0086       ? m_monopdsocket->peerPort()
0087       : -1;
0088 }
0089 
0090 bool AtlantikNetwork::isConnected() const
0091 {
0092     return m_monopdsocket && m_monopdsocket->state() == QAbstractSocket::ConnectedState;
0093 }
0094 
0095 void AtlantikNetwork::slotwriteData(const QString &msg)
0096 {
0097     Q_EMIT networkEvent(msg, ET_NetOut);
0098 
0099 }
0100 
0101 void AtlantikNetwork::slotRead()
0102 {
0103     if (!m_monopdstream.device())
0104         return;
0105 
0106     const QString line = m_monopdstream.readLine();
0107     if (!line.isNull())
0108     {
0109         
0110         processMsg(line);
0111         
0112         // There might be more data; Do we really need this?
0113         QTimer::singleShot(0, this, SLOT(slotRead()));
0114     }
0115     else
0116     {
0117         // Maximum message size. Messages won't get bigger than 32k anyway, so
0118         // if we didn't receive a newline by now, we probably won't anyway.
0119         if (m_monopdsocket->bytesAvailable() > (1024 * 32))
0120             m_monopdsocket->flush();
0121     }
0122 }
0123 
0124 
0125 
0126 void AtlantikNetwork::serverConnect(const QString &host, int port)
0127 {
0128     Q_EMIT msgStatus(i18n("Connecting to %1:%2...", host, QString::number(port)), ET_NetGeneric);
0129     m_host = host;
0130     m_port = port;
0131     m_monopdsocket->connectToHost(host, port);
0132 }
0133 
0134 void AtlantikNetwork::slotLookupFinished()
0135 {
0136     Q_EMIT msgStatus(i18n("Server host name lookup finished..."), ET_NetGeneric);
0137 }
0138 
0139 void AtlantikNetwork::slotConnectionSuccess()
0140 {
0141     Q_EMIT msgStatus(i18n("Connected to %1:%2.", m_host, QString::number(m_port)), ET_NetConnected);
0142 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0143     m_monopdstream.setCodec(QTextCodec::codecForName("UTF-8"));
0144 #endif
0145     m_monopdstream.setDevice(m_monopdsocket);
0146     connect(m_monopdsocket, SIGNAL(readyRead()), this, SLOT(slotRead()));
0147 
0148     Q_EMIT connectionSuccess();
0149 }
0150 
0151 void AtlantikNetwork::slotConnectionFailed(QAbstractSocket::SocketError error)
0152 {
0153     Q_EMIT connectionFailed(error);
0154     Q_EMIT msgStatus(i18n("Connection failed! Error code: %1", error), ET_NetError);
0155 }
0156 
0157 void AtlantikNetwork::slotDisconnected()
0158 {
0159     Q_EMIT msgStatus(i18n("Disconnected from %1:%2.", m_host, QString::number(m_port)), ET_NetGeneric);
0160     Q_EMIT disconnected();
0161 }
0162 
0163 void AtlantikNetwork::writeData(const QString &data) {
0164 
0165     Q_EMIT networkEvent(data, ET_NetOut);
0166     //data.append("\n");
0167     m_monopdstream << data << '\n';
0168     m_monopdstream.flush();
0169     qCDebug(LIBATLANTIKCLIENT_LOG) << "writing data:" << data;
0170 
0171 }
0172 
0173 //Atlantik-specific stuff follows here
0174 //Perhaps it is better to separate this out in another class
0175 
0176 void AtlantikNetwork::rollDice()
0177 {
0178         writeData(QStringLiteral(".r"));
0179 }
0180 
0181 void AtlantikNetwork::buyEstate()
0182 {
0183         writeData(QStringLiteral(".eb"));
0184 }
0185 
0186 void AtlantikNetwork::auctionEstate()
0187 {
0188         writeData(QStringLiteral(".ea"));
0189 }
0190 
0191 void AtlantikNetwork::startGame()
0192 {
0193         writeData(QStringLiteral(".gs"));
0194 }
0195 
0196 void AtlantikNetwork::reconnect(const QString &cookie)
0197 {
0198         writeData(QStringLiteral(".R") + cookie);
0199 }
0200 
0201 void AtlantikNetwork::leaveGame()
0202 {
0203         writeData(QStringLiteral(".gx"));
0204 }
0205 
0206 void AtlantikNetwork::endTurn()
0207 {
0208         writeData(QStringLiteral(".E"));
0209 }
0210 
0211 void AtlantikNetwork::setName(const QString &name)
0212 {
0213         // Almost deprecated, will be replaced by libmonopdprotocol
0214         writeData(QStringLiteral(".n%1").arg(name));
0215         qCDebug(LIBATLANTIKCLIENT_LOG) << "set name to:" << name;
0216 }
0217 
0218 void AtlantikNetwork::tokenConfirmation(Estate *estate)
0219 {
0220         writeData(QStringLiteral(".t%1").arg(estate ? estate->id() : -1));
0221 }
0222 
0223 void AtlantikNetwork::estateToggleMortgage(Estate *estate)
0224 {
0225         writeData(QStringLiteral(".em%1").arg(estate ? estate->id() : -1));
0226 }
0227 
0228 void AtlantikNetwork::estateHouseBuy(Estate *estate)
0229 {
0230         writeData(QStringLiteral(".hb%1").arg(estate ? estate->id() : -1));
0231 }
0232 
0233 void AtlantikNetwork::estateHouseSell(Estate *estate)
0234 {
0235         writeData(QStringLiteral(".hs%1").arg(estate ? estate->id() : -1));
0236 }
0237 
0238 void AtlantikNetwork::estateSell(Estate *estate)
0239 {
0240         writeData(QStringLiteral(".es%1").arg(estate ? estate->id() : -1));
0241 }
0242 
0243 void AtlantikNetwork::newGame(const QString &gameType)
0244 {
0245         writeData(QStringLiteral(".gn%1").arg(gameType));
0246 }
0247 
0248 void AtlantikNetwork::joinGame(int gameId)
0249 {
0250         writeData(QStringLiteral(".gj%1").arg(gameId));
0251         qCDebug(LIBATLANTIKCLIENT_LOG) << "joining game" << gameId;
0252 }
0253 
0254 void AtlantikNetwork::watchGame(int gameId)
0255 {
0256         writeData(QStringLiteral(".gS%1").arg(gameId));
0257         qCDebug(LIBATLANTIKCLIENT_LOG) << "watching game" << gameId;
0258 }
0259 
0260 void AtlantikNetwork::cmdChat(const QString &msg)
0261 {
0262         writeData(msg);
0263 }
0264 
0265 void AtlantikNetwork::newTrade(Player *player)
0266 {
0267         writeData(QStringLiteral(".Tn%1").arg(player ? player->id() : -1));
0268 }
0269 
0270 void AtlantikNetwork::kickPlayer(Player *player)
0271 {
0272         writeData(QStringLiteral(".gk%1").arg(player ? player->id() : -1));
0273 }
0274 
0275 void AtlantikNetwork::tradeUpdateEstate(Trade *trade, Estate *estate, Player *player)
0276 {
0277         writeData(QStringLiteral(".Te%1:%2:%3").arg(trade ? trade->tradeId() : -1).arg(estate ? estate->id() : -1).arg(player ? player->id() : -1));
0278 }
0279 
0280 void AtlantikNetwork::tradeUpdateMoney(Trade *trade, unsigned int money, Player *pFrom, Player *pTo)
0281 {
0282         writeData(QStringLiteral(".Tm%1:%2:%3:%4").arg(trade ? trade->tradeId() : -1).arg(pFrom ? pFrom->id() : -1).arg(pTo ? pTo->id() : -1).arg(money));
0283 }
0284 
0285 void AtlantikNetwork::tradeUpdateCard(Trade *trade, Card *card, Player *pTo)
0286 {
0287         writeData(QStringLiteral(".Tc%1:%2:%3").arg(trade ? trade->tradeId() : -1).arg(card ? card->cardId() : -1).arg(pTo ? pTo->id() : -1));
0288 }
0289 
0290 void AtlantikNetwork::tradeReject(Trade *trade)
0291 {
0292         writeData(QStringLiteral(".Tr%1").arg(trade ? trade->tradeId() : -1));
0293 }
0294 
0295 void AtlantikNetwork::tradeAccept(Trade *trade)
0296 {
0297         writeData(QStringLiteral(".Ta%1:%2").arg(trade ? trade->tradeId() : -1).arg(trade ? trade->revision() : -1));
0298 }
0299 
0300 void AtlantikNetwork::auctionBid(Auction *auction, int amount)
0301 {
0302         writeData(QStringLiteral(".ab%1:%2").arg(auction ? auction->auctionId() : -1).arg(amount));
0303 }
0304 
0305 void AtlantikNetwork::setImage(const QString &name)
0306 {
0307         writeData(QStringLiteral(".pi%1").arg(name));
0308 }
0309 
0310 void AtlantikNetwork::jailPay()
0311 {
0312         writeData(QStringLiteral(".jp"));
0313 }
0314 
0315 void AtlantikNetwork::jailRoll()
0316 {
0317         writeData(QStringLiteral(".jr"));
0318 }
0319 
0320 void AtlantikNetwork::jailCard()
0321 {
0322         writeData(QStringLiteral(".jc"));
0323 }
0324 
0325 void AtlantikNetwork::changeOption(int configId, const QString &value)
0326 {
0327         writeData(QStringLiteral(".gc%1:%2").arg(configId).arg(value));
0328 }
0329 
0330 
0331 void AtlantikNetwork::processMsg(const QString &msg) {
0332     Q_EMIT networkEvent(msg, ET_NetIn);
0333     qCDebug(LIBATLANTIKCLIENT_LOG) << msg;
0334     QDomDocument dom;
0335     dom.setContent(msg);
0336     QDomElement e = dom.documentElement();
0337     if (e.tagName() != QLatin1String("monopd")) {
0338         // Invalid data, request full update from server
0339         writeData(QStringLiteral(".f"));
0340         return;
0341     }
0342     QDomNode n = e.firstChild();
0343     processNode(n);
0344     if (LIBATLANTIKCLIENT_LOG().isDebugEnabled())
0345         m_atlanticCore->printDebug();
0346 }
0347 
0348 void AtlantikNetwork::processNode(QDomNode n) {
0349     QDomAttr a;
0350 
0351     for ( ; !n.isNull() ; n = n.nextSibling() ) {
0352         QDomElement e = n.toElement();
0353         if(!e.isNull()) {
0354             if (e.tagName() == QLatin1String("server")) {
0355                 a = e.attributeNode(QStringLiteral("version"));
0356                 if ( !a.isNull() )
0357                     m_serverVersion = a.value();
0358                     qCDebug(LIBATLANTIKCLIENT_LOG) << "receivedHandshake";
0359                 Q_EMIT receivedHandshake();
0360             } else if (e.tagName() == QLatin1String("msg")) {
0361                 a = e.attributeNode(QStringLiteral("type"));
0362                 if (!a.isNull()) {
0363                     if (a.value() == QLatin1String("error"))
0364                         Q_EMIT msgError(e.attributeNode(QStringLiteral("value")).value());
0365                     else if (a.value() == QLatin1String("info"))
0366                         Q_EMIT msgInfo(e.attributeNode(QStringLiteral("value")).value());
0367                     else if (a.value() == QLatin1String("chat"))
0368                         Q_EMIT msgChat(e.attributeNode(QStringLiteral("author")).value(), e.attributeNode(QStringLiteral("value")).value());
0369                 }
0370             } else if (e.tagName() == QLatin1String("display")) {
0371                 Estate *estate = nullptr;
0372                 bool hasEstateId = false;
0373 
0374                 a = e.attributeNode(QStringLiteral("estateid"));
0375                 if (!a.isNull()) {
0376                     estate = m_atlanticCore->findEstate(a.value().toInt());
0377                     hasEstateId = true;
0378                 }
0379                 if (hasEstateId) {
0380                     Q_EMIT displayDetails(e.attributeNode(QStringLiteral("text")).value(), e.attributeNode(QStringLiteral("cleartext")).value().toInt(), e.attributeNode(QStringLiteral("clearbuttons")).value().toInt(), estate);
0381                 } else {
0382                     Q_EMIT displayText(e.attributeNode(QStringLiteral("text")).value(), e.attributeNode(QStringLiteral("cleartext")).value().toInt(), e.attributeNode(QStringLiteral("clearbuttons")).value().toInt());
0383                 }
0384 
0385                     bool hasButtons = false;
0386                     for( QDomNode nButtons = n.firstChild() ; !nButtons.isNull() ; nButtons = nButtons.nextSibling() ) {
0387                         QDomElement eButton = nButtons.toElement();
0388                         if (!eButton.isNull() && eButton.tagName() == QLatin1String("button")) {
0389                             Q_EMIT addCommandButton(eButton.attributeNode(QStringLiteral("command")).value(), eButton.attributeNode(QStringLiteral("caption")).value(), eButton.attributeNode(QStringLiteral("enabled")).value().toInt());
0390                             hasButtons = true;
0391                         }
0392                     }
0393 
0394                     if (!hasButtons)
0395                         Q_EMIT addCloseButton();
0396             } else if (e.tagName() == QLatin1String("client")) {
0397                 a = e.attributeNode(QStringLiteral("playerid"));
0398                 if (!a.isNull())
0399                     m_playerId = a.value().toInt();
0400 
0401                 a = e.attributeNode(QStringLiteral("cookie"));
0402                 if (!a.isNull())
0403                     Q_EMIT clientCookie(a.value());
0404             } else if (e.tagName() == QLatin1String("configupdate")) {
0405                 Game *game = nullptr;
0406                 a = e.attributeNode(QStringLiteral("gameid"));
0407                 if (!a.isNull()) {
0408                     int gameId = a.value().toInt();
0409                     game = m_atlanticCore->findGame(gameId);
0410                 }
0411 
0412                 a = e.attributeNode(QStringLiteral("configid"));
0413                 if (!a.isNull() && game) {
0414                     int configId = a.value().toInt();
0415                     ConfigOption *configOption = game->findConfigOption(configId);
0416                     bool created = false;
0417                     if (!configOption) {
0418                         configOption = new ConfigOption(configId);
0419                         created = true;
0420                     }
0421 
0422                     a = e.attributeNode(QStringLiteral("name"));
0423                     if (configOption && !a.isNull())
0424                         configOption->setName(a.value());
0425 
0426                     a = e.attributeNode(QStringLiteral("description"));
0427                     if (configOption && !a.isNull())
0428                         configOption->setDescription(a.value());
0429 
0430                     a = e.attributeNode(QStringLiteral("edit"));
0431                     if (configOption && !a.isNull())
0432                         configOption->setEdit(a.value().toInt());
0433 
0434                     a = e.attributeNode(QStringLiteral("type"));
0435                     if (configOption && !a.isNull())
0436                         configOption->setType(a.value());
0437 
0438                     a = e.attributeNode(QStringLiteral("value"));
0439                     if (configOption && !a.isNull())
0440                         configOption->setValue(a.value());
0441 
0442                     configOption->update();
0443                     if (created)
0444                         game->addConfigOption(configOption);
0445                 }
0446             } else if (e.tagName() == QLatin1String("deletegame")) {
0447                 a = e.attributeNode(QStringLiteral("gameid"));
0448                 if (!a.isNull()) {
0449                     int gameId = a.value().toInt();
0450 
0451                     Game *game = m_atlanticCore->findGame(gameId);
0452                     if (game)
0453                         m_atlanticCore->removeGame(game);
0454                 }
0455             } else if (e.tagName() == QLatin1String("gameupdate")) {
0456                 int gameId = -1;
0457 
0458                 a = e.attributeNode(QStringLiteral("gameid"));
0459                 if (!a.isNull()) {
0460                     gameId = a.value().toInt();
0461 
0462                     Player *playerSelf = m_atlanticCore->playerSelf();
0463                     if ( playerSelf && playerSelf->game() )
0464                         qCDebug(LIBATLANTIKCLIENT_LOG) << "gameupdate for" << gameId << "with playerSelf in game" << playerSelf->game()->id();
0465                     else
0466                         qCDebug(LIBATLANTIKCLIENT_LOG) << "gameupdate for" << gameId;
0467 
0468 
0469                     Game *game = nullptr;
0470                     if (gameId == -1) {
0471                         a = e.attributeNode(QStringLiteral("gametype"));
0472                         if ( !a.isNull() && !(game = m_atlanticCore->findGame(a.value())) )
0473                             game = m_atlanticCore->newGame(gameId, a.value());
0474                     } else if (!(game = m_atlanticCore->findGame(gameId)))
0475                         game = m_atlanticCore->newGame(gameId);
0476 
0477                     a = e.attributeNode(QStringLiteral("canbejoined"));
0478                     if (game && !a.isNull())
0479                         game->setCanBeJoined(a.value().toInt());
0480 
0481                     a = e.attributeNode(QStringLiteral("canbewatched"));
0482                     if (game && !a.isNull())
0483                         game->setCanBeWatched(a.value().toInt());
0484 
0485                     a = e.attributeNode(QStringLiteral("description"));
0486                     if (game && !a.isNull())
0487                         game->setDescription(a.value());
0488 
0489                     a = e.attributeNode(QStringLiteral("name"));
0490                     if (game && !a.isNull())
0491                         game->setName(a.value());
0492 
0493                     a = e.attributeNode(QStringLiteral("players"));
0494                     if (game && !a.isNull())
0495                         game->setPlayers(a.value().toInt());
0496 
0497                     a = e.attributeNode(QStringLiteral("master"));
0498                     if (game && !a.isNull()) {
0499                         // Ensure setMaster succeeds by creating player if necessary
0500                         Player *player = m_atlanticCore->findPlayer( a.value().toInt() );
0501                         if ( !player )
0502                             player = m_atlanticCore->newPlayer( a.value().toInt() );
0503                         game->setMaster( player );
0504                     }
0505 
0506                     QString status = e.attributeNode(QStringLiteral("status")).value();
0507                     if ( m_serverVersion.left(4) == QLatin1String("0.9.") || (playerSelf && playerSelf->game() == game) ) {
0508                         if (status == QLatin1String("config"))
0509                             Q_EMIT gameConfig();
0510                         else if (status == QLatin1String("init"))
0511                             Q_EMIT gameInit();
0512                         else if (status == QLatin1String("run"))
0513                             Q_EMIT gameRun();
0514                         else if (status == QLatin1String("end"))
0515                             Q_EMIT gameEnd();
0516                     }
0517 
0518                     if (game)
0519                         game->update();
0520                 }
0521             } else if (e.tagName() == QLatin1String("deleteplayer")) {
0522                 a = e.attributeNode(QStringLiteral("playerid"));
0523                 if (!a.isNull()) {
0524                     int playerId = a.value().toInt();
0525 
0526                     Player *player = m_atlanticCore->findPlayer(playerId);
0527                     if (player) {
0528                         m_playerLocationMap.remove(player);
0529                         m_atlanticCore->removePlayer(player);
0530                     }
0531                 }
0532             } else if (e.tagName() == QLatin1String("playerupdate")) {
0533                 int playerId = -1;
0534 
0535                 a = e.attributeNode(QStringLiteral("playerid"));
0536                 if (!a.isNull()) {
0537                     playerId = a.value().toInt();
0538 
0539                     Player *player;
0540                     if (!(player = m_atlanticCore->findPlayer(playerId)))
0541                         player = m_atlanticCore->newPlayer( playerId, (m_playerId == playerId) );
0542                     else if (m_playerId == playerId)
0543                         m_atlanticCore->setPlayerSelf(player);
0544 
0545                     // Update player name
0546                     a = e.attributeNode(QStringLiteral("name"));
0547                     if (player && !a.isNull())
0548                         player->setName(a.value());
0549 
0550                     // Update player game
0551                     a = e.attributeNode(QStringLiteral("game"));
0552                     if (player && !a.isNull()) {
0553                         int gameId = a.value().toInt();
0554                         if (gameId == -1)
0555                             player->setGame( nullptr );
0556                         else {
0557                             // Ensure setGame succeeds by creating game if necessary
0558                             Game *game = m_atlanticCore->findGame(a.value().toInt());
0559                             if (!game)
0560                                 game = m_atlanticCore->newGame(a.value().toInt()); //
0561                             player->setGame( game );
0562                         }
0563                     }
0564 
0565                     // Update player host
0566                     a = e.attributeNode(QStringLiteral("host"));
0567                     if (player && !a.isNull())
0568                         player->setHost(a.value());
0569 
0570                     // Update player image/token
0571                     a = e.attributeNode(QStringLiteral("image"));
0572                     if (player && !a.isNull())
0573                         player->setImage(a.value());
0574 
0575                     // Update player money
0576                     a = e.attributeNode(QStringLiteral("money"));
0577                     if (player && !a.isNull())
0578                         player->setMoney(a.value().toInt());
0579 
0580                     a = e.attributeNode(QStringLiteral("bankrupt"));
0581                     if (player && !a.isNull())
0582                         player->setBankrupt(a.value().toInt());
0583 
0584                     a = e.attributeNode(QStringLiteral("hasdebt"));
0585                     if (player && !a.isNull())
0586                         player->setHasDebt(a.value().toInt());
0587 
0588                     a = e.attributeNode(QStringLiteral("hasturn"));
0589                     if (player && !a.isNull())
0590                         player->setHasTurn(a.value().toInt());
0591 
0592                     // Update whether player can roll
0593                     a = e.attributeNode(QStringLiteral("can_roll"));
0594                     if (player && !a.isNull())
0595                         player->setCanRoll(a.value().toInt());
0596 
0597                     // Update whether player can buy
0598                     a = e.attributeNode(QStringLiteral("can_buyestate"));
0599                     if (player && !a.isNull())
0600                         player->setCanBuy(a.value().toInt());
0601 
0602                     // Update whether player can auction
0603                     a = e.attributeNode(QStringLiteral("canauction"));
0604                     if (player && !a.isNull())
0605                         player->setCanAuction(a.value().toInt());
0606 
0607                     // Update whether player can use a card
0608                     a = e.attributeNode(QStringLiteral("canusecard"));
0609                     if (player && !a.isNull())
0610                         player->setCanUseCard(a.value().toInt());
0611 
0612                     // Update whether player is jailed
0613                     a = e.attributeNode(QStringLiteral("jailed"));
0614                     if (player && !a.isNull()) {
0615                         player->setInJail(a.value().toInt());
0616                         // TODO: emit signal with player ptr so board can setText and display something
0617                     }
0618 
0619                     // Update whether player is a spectator
0620                     a = e.attributeNode(QStringLiteral("spectator"));
0621                     if (player && !a.isNull())
0622                         player->setSpectator(a.value().toInt());
0623 
0624                     // Update player location
0625                     a = e.attributeNode(QStringLiteral("location"));
0626                     if (!a.isNull()) {
0627                         m_playerLocationMap.insert(player, a.value().toInt());
0628 
0629                         bool directMove = false;
0630 
0631                         Estate *estate = m_atlanticCore->findEstate(a.value().toInt());
0632 
0633                         a = e.attributeNode(QStringLiteral("directmove"));
0634                         if (!a.isNull())
0635                             directMove = a.value().toInt();
0636 
0637                         if (player && estate) {
0638                             if (directMove)
0639                                 player->setLocation(estate);
0640                             else
0641                                 player->setDestination(estate);
0642                         }
0643                     }
0644 
0645                     if (player)
0646                         player->update();
0647                 }
0648             } else if (e.tagName() == QLatin1String("estategroupupdate")) {
0649                 a = e.attributeNode(QStringLiteral("groupid"));
0650                 if (!a.isNull()) {
0651                     int groupId = a.value().toInt();
0652 
0653                     EstateGroup *estateGroup = nullptr;
0654                     bool b_newEstateGroup = false;
0655 
0656                     if (!(estateGroup = m_atlanticCore->findEstateGroup(groupId))) {
0657                         // Create EstateGroup object
0658                         estateGroup = m_atlanticCore->newEstateGroup(a.value().toInt());
0659                         b_newEstateGroup = true;
0660                     }
0661 
0662                     a = e.attributeNode(QStringLiteral("name"));
0663                     if (estateGroup && !a.isNull())
0664                         estateGroup->setName(a.value());
0665 
0666                     // Emit signal so GUI implementations can create view(s)
0667                     // TODO:  port to atlanticcore and create view there
0668                     if (estateGroup) {
0669                         if (b_newEstateGroup)
0670                             Q_EMIT newEstateGroup(estateGroup);
0671                         estateGroup->update();
0672                     }
0673                 }
0674             } else if (e.tagName() == QLatin1String("estateupdate")) {
0675                 int estateId = -1;
0676 
0677                 a = e.attributeNode(QStringLiteral("estateid"));
0678                 if (!a.isNull()) {
0679                     estateId = a.value().toInt();
0680 
0681                     Estate *estate = nullptr;
0682                     bool b_newEstate = false;
0683 
0684                     // FIXME: allow any estateId, GUI should not use it to determin its geometry
0685                     if (estateId >= 0 && estateId < 100 && !(estate = m_atlanticCore->findEstate(a.value().toInt()))) {
0686                         // Create estate object
0687                         estate = m_atlanticCore->newEstate(estateId);
0688                         b_newEstate = true;
0689 
0690                         QObject::connect(estate, SIGNAL(estateToggleMortgage(Estate *)), this, SLOT(estateToggleMortgage(Estate *)));
0691                         QObject::connect(estate, SIGNAL(estateHouseBuy(Estate *)), this, SLOT(estateHouseBuy(Estate *)));
0692                         QObject::connect(estate, SIGNAL(estateHouseSell(Estate *)), this, SLOT(estateHouseSell(Estate *)));
0693                         QObject::connect(estate, SIGNAL(estateSell(Estate *)), this, SLOT(estateSell(Estate *)));
0694                         QObject::connect(estate, SIGNAL(newTrade(Player *)), this, SLOT(newTrade(Player *)));
0695 
0696                         // Players without estate should get one
0697                         foreach (Player *player, m_atlanticCore->players())
0698                             if (m_playerLocationMap.value(player) == estate->id())
0699                                 player->setLocation(estate);
0700                     }
0701 
0702                     a = e.attributeNode(QStringLiteral("name"));
0703                     if (estate && !a.isNull())
0704                         estate->setName(a.value());
0705 
0706                     a = e.attributeNode(QStringLiteral("color"));
0707                     if (estate && !a.isNull() && !a.value().isEmpty())
0708                         estate->setColor(a.value());
0709 
0710                     a = e.attributeNode(QStringLiteral("bgcolor"));
0711                     if (estate && !a.isNull())
0712                         estate->setBgColor(a.value());
0713 
0714                     a = e.attributeNode(QStringLiteral("owner"));
0715                     Player *player = m_atlanticCore->findPlayer(a.value().toInt());
0716                     if (estate && !a.isNull())
0717                         estate->setOwner(player);
0718 
0719                     a = e.attributeNode(QStringLiteral("houses"));
0720                     if (estate && !a.isNull())
0721                         estate->setHouses(a.value().toInt());
0722 
0723                     a = e.attributeNode(QStringLiteral("mortgaged"));
0724                     if (estate && !a.isNull())
0725                         estate->setIsMortgaged(a.value().toInt());
0726 
0727                     a = e.attributeNode(QStringLiteral("group"));
0728                     if (!a.isNull()) {
0729                         EstateGroup *estateGroup = m_atlanticCore->findEstateGroup(a.value().toInt());
0730                         if (estate)
0731                             estate->setEstateGroup(estateGroup);
0732                     }
0733 
0734                     a = e.attributeNode(QStringLiteral("can_toggle_mortgage"));
0735                     if (estate && !a.isNull())
0736                         estate->setCanToggleMortgage(a.value().toInt());
0737 
0738                     a = e.attributeNode(QStringLiteral("can_be_owned"));
0739                     if (estate && !a.isNull())
0740                         estate->setCanBeOwned(a.value().toInt());
0741 
0742                     a = e.attributeNode(QStringLiteral("can_buy_houses"));
0743                     if (estate && !a.isNull())
0744                         estate->setCanBuyHouses(a.value().toInt());
0745 
0746                     a = e.attributeNode(QStringLiteral("can_sell_houses"));
0747                     if (estate && !a.isNull())
0748                         estate->setCanSellHouses(a.value().toInt());
0749 
0750                     a = e.attributeNode(QStringLiteral("price"));
0751                     if (estate && !a.isNull())
0752                         estate->setPrice(a.value().toInt());
0753 
0754                     a = e.attributeNode(QStringLiteral("houseprice"));
0755                     if (estate && !a.isNull())
0756                         estate->setHousePrice(a.value().toInt());
0757 
0758                     a = e.attributeNode(QStringLiteral("sellhouseprice"));
0759                     if (estate && !a.isNull())
0760                         estate->setHouseSellPrice(a.value().toInt());
0761 
0762                     a = e.attributeNode(QStringLiteral("mortgageprice"));
0763                     if (estate && !a.isNull())
0764                         estate->setMortgagePrice(a.value().toInt());
0765 
0766                     a = e.attributeNode(QStringLiteral("unmortgageprice"));
0767                     if (estate && !a.isNull())
0768                         estate->setUnmortgagePrice(a.value().toInt());
0769 
0770                     a = e.attributeNode(QStringLiteral("money"));
0771                     if (estate && !a.isNull())
0772                         estate->setMoney(a.value().toInt());
0773 
0774                     a = e.attributeNode(QStringLiteral("icon"));
0775                     if (estate && !a.isNull())
0776                         estate->setIcon(a.value());
0777 
0778                     // Emit signal so GUI implementations can create view(s)
0779                     // TODO:  port to atlanticcore and create view there
0780                     if (estate) {
0781                         if (b_newEstate)
0782                             Q_EMIT newEstate(estate);
0783                         estate->update();
0784                     }
0785                 }
0786             } else if (e.tagName() == QLatin1String("tradeupdate")) {
0787                 a = e.attributeNode(QStringLiteral("tradeid"));
0788                 if (!a.isNull()) {
0789                     int tradeId = a.value().toInt();
0790 
0791                     Trade *trade = m_atlanticCore->findTrade(tradeId);
0792                     if (!trade) {
0793                         // Create trade object
0794                         trade = m_atlanticCore->newTrade(tradeId);
0795 
0796                         QObject::connect(trade, SIGNAL(updateEstate(Trade *, Estate *, Player *)), this, SLOT(tradeUpdateEstate(Trade *, Estate *, Player *)));
0797                         QObject::connect(trade, SIGNAL(updateMoney(Trade *, unsigned int, Player *, Player *)), this, SLOT(tradeUpdateMoney(Trade *, unsigned int, Player *, Player *)));
0798                         QObject::connect(trade, SIGNAL(updateCard(Trade *, Card *, Player *)), this, SLOT(tradeUpdateCard(Trade *, Card *, Player *)));
0799                         QObject::connect(trade, SIGNAL(reject(Trade *)), this, SLOT(tradeReject(Trade *)));
0800                         QObject::connect(trade, SIGNAL(accept(Trade *)), this, SLOT(tradeAccept(Trade *)));
0801                     }
0802 
0803                     a = e.attributeNode(QStringLiteral("revision"));
0804                     if (trade && !a.isNull())
0805                         trade->setRevision(a.value().toInt());
0806 
0807                     QString type = e.attributeNode(QStringLiteral("type")).value();
0808                     if (type == QLatin1String("new")) {
0809                         // TODO: trade->setActor
0810                         // Player *player = m_atlanticCore->findPlayer(e.attributeNode(QStringLiteral("actor")).value().toInt());
0811                         // if (trade && player)
0812                         //      trade->setActor(player);
0813 
0814                         QDomNode n_player = n.firstChild();
0815                         while(!n_player.isNull()) {
0816                             QDomElement e_player = n_player.toElement();
0817                             if (!e_player.isNull() && e_player.tagName() == QLatin1String("tradeplayer")) {
0818                                 Player *player = m_atlanticCore->findPlayer(e_player.attributeNode(QStringLiteral("playerid")).value().toInt());
0819                                 if (trade && player) {
0820                                     trade->addPlayer(player);
0821                                     QObject::connect(m_atlanticCore, SIGNAL(removePlayer(Player *)), trade, SLOT(removePlayer(Player *)));
0822                                 }
0823                             }
0824                             n_player = n_player.nextSibling();
0825                         }
0826                     } else if (type == QLatin1String("accepted") && trade)
0827                         Q_EMIT msgTradeUpdateAccepted(trade);
0828                     else if (type == QLatin1String("completed") && trade) {
0829                         m_atlanticCore->removeTrade(trade);
0830                         trade = nullptr;
0831                     } else if (type == QLatin1String("rejected")) {
0832                         Player *player = m_atlanticCore->findPlayer(e.attributeNode(QStringLiteral("actor")).value().toInt());
0833                         if (trade)
0834                             trade->reject(player);
0835                         if ( player && player == m_atlanticCore->playerSelf() ) {
0836                             m_atlanticCore->removeTrade(trade);
0837                             trade = nullptr;
0838                         }
0839                     } else {
0840                         // No type specified, edit is implied.
0841 
0842                         QDomNode n_child = n.firstChild();
0843                         while(!n_child.isNull()) {
0844                             QDomElement e_child = n_child.toElement();
0845                             if (!e_child.isNull()) {
0846                                 if (e_child.tagName() == QLatin1String("tradeplayer")) {
0847                                     a = e_child.attributeNode(QStringLiteral("playerid"));
0848                                     if (!a.isNull()) {
0849                                         Player *player = m_atlanticCore->findPlayer(a.value().toInt());
0850 
0851                                         a = e_child.attributeNode(QStringLiteral("accept"));
0852                                         if (trade && player && !a.isNull())
0853                                             trade->updateAccept(player, (bool)(a.value().toInt()));
0854                                     }
0855                                 } else if (e_child.tagName() == QLatin1String("tradeestate")) {
0856                                     a = e_child.attributeNode(QStringLiteral("estateid"));
0857                                     if (!a.isNull()) {
0858                                         Estate *estate = m_atlanticCore->findEstate(a.value().toInt());
0859                                         a = e_child.attributeNode(QStringLiteral("targetplayer"));
0860                                         if (!a.isNull()) {
0861                                             Player *player = m_atlanticCore->findPlayer(a.value().toInt());
0862                                             // Allow NULL player, it will remove the component
0863                                             if (trade && estate)
0864                                                 trade->updateEstate(estate, player);
0865                                         }
0866                                     }
0867                                 } else if (e_child.tagName() == QLatin1String("trademoney")) {
0868                                     Player *pFrom = nullptr, *pTo = nullptr;
0869 
0870                                     a = e_child.attributeNode(QStringLiteral("playerfrom"));
0871                                     if (!a.isNull())
0872                                         pFrom = m_atlanticCore->findPlayer(a.value().toInt());
0873 
0874                                     a = e_child.attributeNode(QStringLiteral("playerto"));
0875                                     if (!a.isNull())
0876                                         pTo = m_atlanticCore->findPlayer(a.value().toInt());
0877 
0878                                     a = e_child.attributeNode(QStringLiteral("money"));
0879                                     qCDebug(LIBATLANTIKCLIENT_LOG) << "tradeupdatemoney" << (pFrom ? "1" : "0") << (pTo ? "1" : "0") << (a.isNull() ? "0" : "1");
0880                                     if (trade && pFrom && pTo && !a.isNull())
0881                                         trade->updateMoney(a.value().toInt(), pFrom, pTo);
0882                                 } else if (e_child.tagName() == QLatin1String("tradecard")) {
0883                                     a = e_child.attributeNode(QStringLiteral("cardid"));
0884                                     if (!a.isNull()) {
0885                                         Card *card = m_atlanticCore->findCard(a.value().toInt());
0886                                         a = e_child.attributeNode(QStringLiteral("targetplayer"));
0887                                         if (!a.isNull()) {
0888                                             Player *player = m_atlanticCore->findPlayer(a.value().toInt());
0889                                             // Allow NULL player, it will remove the component
0890                                             if (trade && card)
0891                                                 trade->updateCard(card, player);
0892                                         }
0893                                     }
0894                                 }
0895                             }
0896                             n_child = n_child.nextSibling();
0897                         }
0898                     }
0899 
0900                     if (trade)
0901                         trade->update();
0902                 }
0903             } else if (e.tagName() == QLatin1String("auctionupdate")) {
0904                 a = e.attributeNode(QStringLiteral("auctionid"));
0905                 if (!a.isNull()) {
0906                     int auctionId = a.value().toInt();
0907 
0908                     Auction *auction = m_atlanticCore->findAuction(auctionId);
0909                     bool b_newAuction = false;
0910                     if (!auction) {
0911                         // Create auction object
0912                         auction = m_atlanticCore->newAuction(auctionId, m_atlanticCore->findEstate(e.attributeNode(QStringLiteral("estateid")).value().toInt()));
0913 
0914                         QObject::connect(auction, SIGNAL(bid(Auction *, int)), this, SLOT(auctionBid(Auction *, int)));
0915 
0916                         b_newAuction = true;
0917                     }
0918 
0919                     a = e.attributeNode(QStringLiteral("highbidder"));
0920                     if (!a.isNull()) {
0921                         Player *player = m_atlanticCore->findPlayer(e.attributeNode(QStringLiteral("highbidder")).value().toInt());
0922                         a = e.attributeNode(QStringLiteral("highbid"));
0923                         if (auction && !a.isNull())
0924                             auction->newBid(player, a.value().toInt());
0925                     }
0926 
0927                     a = e.attributeNode(QStringLiteral("status"));
0928                     if (auction && !a.isNull()) {
0929                         int status = a.value().toInt();
0930                         auction->setStatus(status);
0931 
0932                         // TODO: find a good way to visually represent "sold!"
0933                         if (status == 3) {
0934                             m_atlanticCore->delAuction(auction);
0935                             auction = nullptr;
0936                         }
0937                     }
0938 
0939                     // Emit signal so GUI implementations can create view(s)
0940                     // TODO:  port to atlanticcore and create view there
0941                     if (auction) {
0942                         if (b_newAuction)
0943                             Q_EMIT newAuction(auction);
0944                         auction->update();
0945                     }
0946                 }
0947             } else if (e.tagName() == QLatin1String("cardupdate")) {
0948                 a = e.attributeNode(QStringLiteral("cardid"));
0949                 if (!a.isNull()) {
0950                     int cardId = a.value().toInt();
0951 
0952                     Card *card;
0953                     if (!(card = m_atlanticCore->findCard(cardId)))
0954                         card = m_atlanticCore->newCard(cardId);
0955 
0956                     // Update card owner
0957                     a = e.attributeNode(QStringLiteral("owner"));
0958                     if (!a.isNull()) {
0959                         Player *player = m_atlanticCore->findPlayer(a.value().toInt());
0960                         card->setOwner(player);
0961                     }
0962 
0963                     // Update card title
0964                     a = e.attributeNode(QStringLiteral("title"));
0965                     if (!a.isNull())
0966                         card->setTitle(a.value());
0967 
0968                     if (card)
0969                         card->update();
0970                 }
0971             } else
0972                 qCDebug(LIBATLANTIKCLIENT_LOG) << "ignored TAG:" << e.tagName();
0973         }
0974         // TODO: remove permanently?
0975         // QDomNode node = n.firstChild();
0976         // processNode(node);
0977     }
0978 }
0979 
0980 #include "moc_atlantik_network.cpp"