QTfrontend/net/newnetclient.cpp
branchsdl2transition
changeset 11342 ed5a6478e710
parent 11046 47a8c19ecb60
child 11466 5dbc0f976b4a
equal deleted inserted replaced
11340:31570b766315 11342:ed5a6478e710
     1 /*
     1 /*
     2  * Hedgewars, a free turn based strategy game
     2  * Hedgewars, a free turn based strategy game
     3  * Copyright (c) 2006-2008 Igor Ulyanov <iulyanov@gmail.com>
     3  * Copyright (c) 2006-2008 Igor Ulyanov <iulyanov@gmail.com>
     4  * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
     4  * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
     5  *
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; version 2 of the License
     8  * the Free Software Foundation; version 2 of the License
     9  *
     9  *
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    13  * GNU General Public License for more details.
    14  *
    14  *
    15  * You should have received a copy of the GNU General Public License
    15  * You should have received a copy of the GNU General Public License
    16  * along with this program; if not, write to the Free Software
    16  * along with this program; if not, write to the Free Software
    17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18  */
    18  */
    19 
    19 
    20 #include <QDebug>
    20 #include <QDebug>
    21 #include <QInputDialog>
    21 #include <QInputDialog>
    22 #include <QCryptographicHash>
    22 #include <QCryptographicHash>
    23 #include <QSortFilterProxyModel>
    23 #include <QSortFilterProxyModel>
       
    24 #include <QUuid>
    24 
    25 
    25 #include "hwconsts.h"
    26 #include "hwconsts.h"
    26 #include "newnetclient.h"
    27 #include "newnetclient.h"
    27 #include "proto.h"
    28 #include "proto.h"
    28 #include "game.h"
    29 #include "game.h"
    29 #include "roomslistmodel.h"
    30 #include "roomslistmodel.h"
    30 #include "playerslistmodel.h"
    31 #include "playerslistmodel.h"
    31 #include "servermessages.h"
    32 #include "servermessages.h"
    32 #include "HWApplication.h"
    33 #include "HWApplication.h"
    33 
    34 
    34 char delimeter='\n';
    35 char delimiter='\n';
    35 
    36 
    36 HWNewNet::HWNewNet() :
    37 HWNewNet::HWNewNet() :
    37     isChief(false),
    38     isChief(false),
    38     m_game_connected(false),
    39     m_game_connected(false),
    39     loginStep(0),
       
    40     netClientState(Disconnected)
    40     netClientState(Disconnected)
    41 {
    41 {
       
    42     m_private_game = false;
       
    43     m_nick_registered = false;
       
    44 
    42     m_roomsListModel = new RoomsListModel(this);
    45     m_roomsListModel = new RoomsListModel(this);
    43 
    46 
    44     m_playersModel = new PlayersListModel(this);
    47     m_playersModel = new PlayersListModel(this);
    45 
    48 
    46     m_lobbyPlayersModel = new QSortFilterProxyModel(this);
    49     m_lobbyPlayersModel = new QSortFilterProxyModel(this);
    69 
    72 
    70 HWNewNet::~HWNewNet()
    73 HWNewNet::~HWNewNet()
    71 {
    74 {
    72     if (m_game_connected)
    75     if (m_game_connected)
    73     {
    76     {
    74         RawSendNet(QString("QUIT%1%2").arg(delimeter).arg("User quit"));
    77         RawSendNet(QString("QUIT%1%2").arg(delimiter).arg("User quit"));
    75         emit disconnected(tr("User quit"));
    78         emit disconnected(tr("User quit"));
    76     }
    79     }
    77     NetSocket.flush();
    80     NetSocket.flush();
    78 }
    81 }
    79 
    82 
    86 }
    89 }
    87 
    90 
    88 void HWNewNet::Disconnect()
    91 void HWNewNet::Disconnect()
    89 {
    92 {
    90     if (m_game_connected)
    93     if (m_game_connected)
    91         RawSendNet(QString("QUIT%1%2").arg(delimeter).arg("User quit"));
    94         RawSendNet(QString("QUIT%1%2").arg(delimiter).arg("User quit"));
    92     m_game_connected = false;
    95     m_game_connected = false;
    93 
    96 
    94     NetSocket.disconnectFromHost();
    97     NetSocket.disconnectFromHost();
    95 }
    98 }
    96 
    99 
   103     }
   106     }
   104 
   107 
   105     myroom = room;
   108     myroom = room;
   106 
   109 
   107     if(password.isEmpty())
   110     if(password.isEmpty())
   108         RawSendNet(QString("CREATE_ROOM%1%2").arg(delimeter).arg(room));
   111         RawSendNet(QString("CREATE_ROOM%1%2").arg(delimiter).arg(room));
   109     else
   112     else
   110         RawSendNet(QString("CREATE_ROOM%1%2%1%3").arg(delimeter).arg(room).arg(password));
   113         RawSendNet(QString("CREATE_ROOM%1%2%1%3").arg(delimiter).arg(room).arg(password));
   111 
   114 
   112     isChief = true;
   115     isChief = true;
   113 }
   116 }
   114 
   117 
   115 void HWNewNet::JoinRoom(const QString & room, const QString &password)
   118 void HWNewNet::JoinRoom(const QString & room, const QString &password)
   121     }
   124     }
   122 
   125 
   123     myroom = room;
   126     myroom = room;
   124 
   127 
   125     if(password.isEmpty())
   128     if(password.isEmpty())
   126         RawSendNet(QString("JOIN_ROOM%1%2").arg(delimeter).arg(room));
   129         RawSendNet(QString("JOIN_ROOM%1%2").arg(delimiter).arg(room));
   127     else
   130     else
   128         RawSendNet(QString("JOIN_ROOM%1%2%1%3").arg(delimeter).arg(room).arg(password));
   131         RawSendNet(QString("JOIN_ROOM%1%2%1%3").arg(delimiter).arg(room).arg(password));
   129 
   132 
   130     isChief = false;
   133     isChief = false;
   131 }
   134 }
   132 
   135 
   133 void HWNewNet::AddTeam(const HWTeam & team)
   136 void HWNewNet::AddTeam(const HWTeam & team)
   134 {
   137 {
   135     QString cmd = QString("ADD_TEAM") + delimeter +
   138     QString cmd = QString("ADD_TEAM") + delimiter +
   136                   team.name() + delimeter +
   139                   team.name() + delimiter +
   137                   QString::number(team.color()) + delimeter +
   140                   QString::number(team.color()) + delimiter +
   138                   team.grave() + delimeter +
   141                   team.grave() + delimiter +
   139                   team.fort() + delimeter +
   142                   team.fort() + delimiter +
   140                   team.voicepack() + delimeter +
   143                   team.voicepack() + delimiter +
   141                   team.flag() + delimeter +
   144                   team.flag() + delimiter +
   142                   QString::number(team.difficulty());
   145                   QString::number(team.difficulty());
   143 
   146 
   144     for(int i = 0; i < HEDGEHOGS_PER_TEAM; ++i)
   147     for(int i = 0; i < HEDGEHOGS_PER_TEAM; ++i)
   145     {
   148     {
   146         cmd.append(delimeter);
   149         cmd.append(delimiter);
   147         cmd.append(team.hedgehog(i).Name);
   150         cmd.append(team.hedgehog(i).Name);
   148         cmd.append(delimeter);
   151         cmd.append(delimiter);
   149         cmd.append(team.hedgehog(i).Hat);
   152         cmd.append(team.hedgehog(i).Hat);
   150     }
   153     }
   151     RawSendNet(cmd);
   154     RawSendNet(cmd);
   152 }
   155 }
   153 
   156 
   154 void HWNewNet::RemoveTeam(const HWTeam & team)
   157 void HWNewNet::RemoveTeam(const HWTeam & team)
   155 {
   158 {
   156     RawSendNet(QString("REMOVE_TEAM") + delimeter + team.name());
   159     RawSendNet(QString("REMOVE_TEAM") + delimiter + team.name());
   157 }
   160 }
   158 
   161 
   159 void HWNewNet::NewNick(const QString & nick)
   162 void HWNewNet::NewNick(const QString & nick)
   160 {
   163 {
   161     RawSendNet(QString("NICK%1%2").arg(delimeter).arg(nick));
   164     RawSendNet(QString("NICK%1%2").arg(delimiter).arg(nick));
   162 }
   165 }
   163 
   166 
   164 void HWNewNet::ToggleReady()
   167 void HWNewNet::ToggleReady()
   165 {
   168 {
   166     RawSendNet(QString("TOGGLE_READY"));
   169     RawSendNet(QString("TOGGLE_READY"));
   168 
   171 
   169 void HWNewNet::SendNet(const QByteArray & buf)
   172 void HWNewNet::SendNet(const QByteArray & buf)
   170 {
   173 {
   171     QString msg = QString(buf.toBase64());
   174     QString msg = QString(buf.toBase64());
   172 
   175 
   173     RawSendNet(QString("EM%1%2").arg(delimeter).arg(msg));
   176     RawSendNet(QString("EM%1%2").arg(delimiter).arg(msg));
   174 }
   177 }
   175 
   178 
   176 void HWNewNet::RawSendNet(const QString & str)
   179 void HWNewNet::RawSendNet(const QString & str)
   177 {
   180 {
   178     RawSendNet(str.toUtf8());
   181     RawSendNet(str.toUtf8());
   236     }
   239     }
   237 }
   240 }
   238 
   241 
   239 void HWNewNet::SendPasswordHash(const QString & hash)
   242 void HWNewNet::SendPasswordHash(const QString & hash)
   240 {
   243 {
   241     RawSendNet(QString("PASSWORD%1%2").arg(delimeter).arg(hash));
   244     // don't send it immediately, only store and check if server asked us for a password
       
   245     m_passwordHash = hash.toAscii();
       
   246 
       
   247     maybeSendPassword();
   242 }
   248 }
   243 
   249 
   244 void HWNewNet::ParseCmd(const QStringList & lst)
   250 void HWNewNet::ParseCmd(const QStringList & lst)
   245 {
   251 {
   246     qDebug() << "Server: " << lst;
   252     qDebug() << "Server: " << lst;
   284     {
   290     {
   285         if(lst.size() < 3 || lst[2].toInt() < cMinServerVersion)
   291         if(lst.size() < 3 || lst[2].toInt() < cMinServerVersion)
   286         {
   292         {
   287             // TODO: Warn user, disconnect
   293             // TODO: Warn user, disconnect
   288             qWarning() << "Server too old";
   294             qWarning() << "Server too old";
   289             RawSendNet(QString("QUIT%1%2").arg(delimeter).arg("Server too old"));
   295             RawSendNet(QString("QUIT%1%2").arg(delimiter).arg("Server too old"));
   290             Disconnect();
   296             Disconnect();
   291             emit disconnected(tr("The server is too old. Disconnecting now."));
   297             emit disconnected(tr("The server is too old. Disconnecting now."));
   292             return;
   298             return;
   293         }
   299         }
   294 
   300 
   295         RawSendNet(QString("NICK%1%2").arg(delimeter).arg(mynick));
   301         RawSendNet(QString("NICK%1%2").arg(delimiter).arg(mynick));
   296         RawSendNet(QString("PROTO%1%2").arg(delimeter).arg(*cProtoVer));
   302         RawSendNet(QString("PROTO%1%2").arg(delimiter).arg(*cProtoVer));
   297         netClientState = Connected;
   303         netClientState = Connected;
   298         m_game_connected = true;
   304         m_game_connected = true;
   299         emit adminAccess(false);
   305         emit adminAccess(false);
   300         return;
   306         return;
   301     }
   307     }
   302 
   308 
       
   309     if (lst[0] == "SERVER_AUTH")
       
   310     {
       
   311         if(lst.size() < 2)
       
   312         {
       
   313             qWarning("Net: Malformed SERVER_AUTH message");
       
   314             return;
       
   315         }
       
   316 
       
   317         if(lst[1] != m_serverHash)
       
   318         {
       
   319             Error("Server authentication error");
       
   320             Disconnect();
       
   321         } else
       
   322         {
       
   323             // empty m_serverHash variable means no authentication was performed
       
   324             // or server passed authentication
       
   325             m_serverHash.clear();
       
   326         }
       
   327 
       
   328         return;
       
   329     }
       
   330 
   303     if (lst[0] == "PING")
   331     if (lst[0] == "PING")
   304     {
   332     {
   305         if (lst.size() > 1)
   333         if (lst.size() > 1)
   306             RawSendNet(QString("PONG%1%2").arg(delimeter).arg(lst[1]));
   334             RawSendNet(QString("PONG%1%2").arg(delimiter).arg(lst[1]));
   307         else
   335         else
   308             RawSendNet(QString("PONG"));
   336             RawSendNet(QString("PONG"));
   309         return;
   337         return;
   310     }
   338     }
   311 
   339 
   448                             m_playersModel->setFlag(nick, PlayersListModel::InRoom, setFlag);
   476                             m_playersModel->setFlag(nick, PlayersListModel::InRoom, setFlag);
   449                         break;
   477                         break;
   450                 // flag indicating if a player is contributor
   478                 // flag indicating if a player is contributor
   451                 case 'c':
   479                 case 'c':
   452                         foreach(const QString & nick, nicks)
   480                         foreach(const QString & nick, nicks)
   453                             m_playersModel->setFlag(nick, PlayersListModel::InRoom, setFlag);
   481                             m_playersModel->setFlag(nick, PlayersListModel::Contributor, setFlag);
   454                         break;
   482                         break;
   455                 // flag indicating if a player has engine running
   483                 // flag indicating if a player has engine running
   456                 case 'g':
   484                 case 'g':
   457                     if(inRoom)
   485                     if(inRoom)
   458                         foreach(const QString & nick, nicks)
   486                         foreach(const QString & nick, nicks)
   513 
   541 
   514         for(int i = 1; i < lst.size(); ++i)
   542         for(int i = 1; i < lst.size(); ++i)
   515         {
   543         {
   516             if (lst[i] == mynick)
   544             if (lst[i] == mynick)
   517             {
   545             {
       
   546                 // check if server is authenticated or no authentication was performed at all
       
   547                 if(!m_serverHash.isEmpty())
       
   548                 {
       
   549                     Error(tr("Server authentication error"));
       
   550 
       
   551                     Disconnect();
       
   552                 }
       
   553 
   518                 netClientState = InLobby;
   554                 netClientState = InLobby;
   519                 RawSendNet(QString("LIST"));
   555                 RawSendNet(QString("LIST"));
   520                 emit connected();
   556                 emit connected();
   521             }
   557             }
   522 
   558 
   543 
   579 
   544         QString roomName = tmp.takeFirst();
   580         QString roomName = tmp.takeFirst();
   545         m_roomsListModel->updateRoom(roomName, tmp);
   581         m_roomsListModel->updateRoom(roomName, tmp);
   546 
   582 
   547         // keep track of room name so correct name is displayed
   583         // keep track of room name so correct name is displayed
   548         if(myroom == roomName)
   584         if(myroom == roomName && myroom != tmp[1])
   549         {
   585         {
   550             myroom = tmp[1];
   586             myroom = tmp[1];
   551             emit roomNameUpdated(myroom);
   587             emit roomNameUpdated(myroom);
   552         }
   588         }
   553 
   589 
   576         return;
   612         return;
   577     }
   613     }
   578 
   614 
   579     if (lst[0] == "ASKPASSWORD")
   615     if (lst[0] == "ASKPASSWORD")
   580     {
   616     {
       
   617         // server should send us salt of at least 16 characters
       
   618 
       
   619         if(lst.size() < 2 || lst[1].size() < 16)
       
   620         {
       
   621             qWarning("Net: Bad ASKPASSWORD message");
       
   622             return;
       
   623         }
       
   624 
   581         emit NickRegistered(mynick);
   625         emit NickRegistered(mynick);
   582         m_nick_registered = true;
   626         m_nick_registered = true;
       
   627 
       
   628         // store server salt
       
   629         // when this variable is set, it is assumed that server asked us for a password
       
   630         m_serverSalt = lst[1];
       
   631         m_clientSalt = QUuid::createUuid().toString();
       
   632 
       
   633         maybeSendPassword();
       
   634 
   583         return;
   635         return;
   584     }
   636     }
   585 
   637 
   586     if (lst[0] == "NOTICE")
   638     if (lst[0] == "NOTICE")
   587     {
   639     {
   694                 qWarning("Net: Bad ADDTEAM message");
   746                 qWarning("Net: Bad ADDTEAM message");
   695                 return;
   747                 return;
   696             }
   748             }
   697             QStringList tmp = lst;
   749             QStringList tmp = lst;
   698             tmp.removeFirst();
   750             tmp.removeFirst();
   699             emit AddNetTeam(tmp);
   751             HWTeam team(tmp);
       
   752             emit AddNetTeam(team);
   700             return;
   753             return;
   701         }
   754         }
   702 
   755 
   703         if (lst[0] == "REMOVE_TEAM")
   756         if (lst[0] == "REMOVE_TEAM")
   704         {
   757         {
   818 
   871 
   819 void HWNewNet::onHedgehogsNumChanged(const HWTeam& team)
   872 void HWNewNet::onHedgehogsNumChanged(const HWTeam& team)
   820 {
   873 {
   821     if (isChief)
   874     if (isChief)
   822         RawSendNet(QString("HH_NUM%1%2%1%3")
   875         RawSendNet(QString("HH_NUM%1%2%1%3")
   823                    .arg(delimeter)
   876                    .arg(delimiter)
   824                    .arg(team.name())
   877                    .arg(team.name())
   825                    .arg(team.numHedgehogs()));
   878                    .arg(team.numHedgehogs()));
   826 }
   879 }
   827 
   880 
   828 void HWNewNet::onTeamColorChanged(const HWTeam& team)
   881 void HWNewNet::onTeamColorChanged(const HWTeam& team)
   829 {
   882 {
   830     if (isChief)
   883     if (isChief)
   831         RawSendNet(QString("TEAM_COLOR%1%2%1%3")
   884         RawSendNet(QString("TEAM_COLOR%1%2%1%3")
   832                    .arg(delimeter)
   885                    .arg(delimiter)
   833                    .arg(team.name())
   886                    .arg(team.name())
   834                    .arg(team.color()));
   887                    .arg(team.color()));
   835 }
   888 }
   836 
   889 
   837 void HWNewNet::onParamChanged(const QString & param, const QStringList & value)
   890 void HWNewNet::onParamChanged(const QString & param, const QStringList & value)
   838 {
   891 {
   839     if (isChief)
   892     if (isChief)
   840         RawSendNet(
   893         RawSendNet(
   841             QString("CFG%1%2%1%3")
   894             QString("CFG%1%2%1%3")
   842             .arg(delimeter)
   895             .arg(delimiter)
   843             .arg(param)
   896             .arg(param)
   844             .arg(value.join(QString(delimeter)))
   897             .arg(value.join(QString(delimiter)))
   845         );
   898         );
   846 }
   899 }
   847 
   900 
   848 void HWNewNet::chatLineToNetWithEcho(const QString& str)
   901 void HWNewNet::chatLineToNetWithEcho(const QString& str)
   849 {
   902 {
   856 
   909 
   857 void HWNewNet::chatLineToNet(const QString& str)
   910 void HWNewNet::chatLineToNet(const QString& str)
   858 {
   911 {
   859     if(str != "")
   912     if(str != "")
   860     {
   913     {
   861         RawSendNet(QString("CHAT") + delimeter + str);
   914         RawSendNet(QString("CHAT") + delimiter + str);
   862         QString action = HWProto::chatStringToAction(str);
   915         QString action = HWProto::chatStringToAction(str);
   863         if (action != NULL)
   916         if (action != NULL)
   864             emit(roomChatAction(mynick, action));
   917             emit(roomChatAction(mynick, action));
   865         else
   918         else
   866             emit(roomChatMessage(mynick, str));
   919             emit(roomChatMessage(mynick, str));
   869 
   922 
   870 void HWNewNet::chatLineToLobby(const QString& str)
   923 void HWNewNet::chatLineToLobby(const QString& str)
   871 {
   924 {
   872     if(str != "")
   925     if(str != "")
   873     {
   926     {
   874         RawSendNet(QString("CHAT") + delimeter + str);
   927         RawSendNet(QString("CHAT") + delimiter + str);
   875         QString action = HWProto::chatStringToAction(str);
   928         QString action = HWProto::chatStringToAction(str);
   876         if (action != NULL)
   929         if (action != NULL)
   877             emit(lobbyChatAction(mynick, action));
   930             emit(lobbyChatAction(mynick, action));
   878         else
   931         else
   879             emit(lobbyChatMessage(mynick, str));
   932             emit(lobbyChatMessage(mynick, str));
   880     }
   933     }
   881 }
   934 }
   882 
   935 
   883 void HWNewNet::SendTeamMessage(const QString& str)
   936 void HWNewNet::SendTeamMessage(const QString& str)
   884 {
   937 {
   885     RawSendNet(QString("TEAMCHAT") + delimeter + str);
   938     RawSendNet(QString("TEAMCHAT") + delimiter + str);
   886 }
   939 }
   887 
   940 
   888 void HWNewNet::askRoomsList()
   941 void HWNewNet::askRoomsList()
   889 {
   942 {
   890     if(netClientState != InLobby)
   943     if(netClientState != InLobby)
   923 void HWNewNet::gameFinished(bool correctly)
   976 void HWNewNet::gameFinished(bool correctly)
   924 {
   977 {
   925     if (netClientState == InGame)
   978     if (netClientState == InGame)
   926     {
   979     {
   927         netClientState = InRoom;
   980         netClientState = InRoom;
   928         RawSendNet(QString("ROUNDFINISHED%1%2").arg(delimeter).arg(correctly ? "1" : "0"));
   981         RawSendNet(QString("ROUNDFINISHED%1%2").arg(delimiter).arg(correctly ? "1" : "0"));
   929     }
   982     }
   930 }
   983 }
   931 
   984 
   932 void HWNewNet::banPlayer(const QString & nick)
   985 void HWNewNet::banPlayer(const QString & nick)
   933 {
   986 {
   934     RawSendNet(QString("BAN%1%2").arg(delimeter).arg(nick));
   987     RawSendNet(QString("BAN%1%2").arg(delimiter).arg(nick));
   935 }
   988 }
   936 
   989 
   937 void HWNewNet::banIP(const QString & ip, const QString & reason, int seconds)
   990 void HWNewNet::banIP(const QString & ip, const QString & reason, int seconds)
   938 {
   991 {
   939     RawSendNet(QString("BANIP%1%2%1%3%1%4").arg(delimeter).arg(ip).arg(reason).arg(seconds));
   992     RawSendNet(QString("BANIP%1%2%1%3%1%4").arg(delimiter).arg(ip).arg(reason).arg(seconds));
   940 }
   993 }
   941 
   994 
   942 void HWNewNet::banNick(const QString & nick, const QString & reason, int seconds)
   995 void HWNewNet::banNick(const QString & nick, const QString & reason, int seconds)
   943 {
   996 {
   944     RawSendNet(QString("BANNICK%1%2%1%3%1%4").arg(delimeter).arg(nick).arg(reason).arg(seconds));
   997     RawSendNet(QString("BANNICK%1%2%1%3%1%4").arg(delimiter).arg(nick).arg(reason).arg(seconds));
   945 }
   998 }
   946 
   999 
   947 void HWNewNet::getBanList()
  1000 void HWNewNet::getBanList()
   948 {
  1001 {
   949     RawSendNet(QByteArray("BANLIST"));
  1002     RawSendNet(QByteArray("BANLIST"));
   950 }
  1003 }
   951 
  1004 
   952 void HWNewNet::removeBan(const QString & b)
  1005 void HWNewNet::removeBan(const QString & b)
   953 {
  1006 {
   954     RawSendNet(QString("UNBAN%1%2").arg(delimeter).arg(b));
  1007     RawSendNet(QString("UNBAN%1%2").arg(delimiter).arg(b));
   955 }
  1008 }
   956 
  1009 
   957 void HWNewNet::kickPlayer(const QString & nick)
  1010 void HWNewNet::kickPlayer(const QString & nick)
   958 {
  1011 {
   959     RawSendNet(QString("KICK%1%2").arg(delimeter).arg(nick));
  1012     RawSendNet(QString("KICK%1%2").arg(delimiter).arg(nick));
   960 }
  1013 }
   961 
  1014 
   962 void HWNewNet::infoPlayer(const QString & nick)
  1015 void HWNewNet::infoPlayer(const QString & nick)
   963 {
  1016 {
   964     RawSendNet(QString("INFO%1%2").arg(delimeter).arg(nick));
  1017     RawSendNet(QString("INFO%1%2").arg(delimiter).arg(nick));
   965 }
  1018 }
   966 
  1019 
   967 void HWNewNet::followPlayer(const QString & nick)
  1020 void HWNewNet::followPlayer(const QString & nick)
   968 {
  1021 {
   969     if (!isInRoom())
  1022     if (!isInRoom())
   970     {
  1023     {
   971         RawSendNet(QString("FOLLOW%1%2").arg(delimeter).arg(nick));
  1024         RawSendNet(QString("FOLLOW%1%2").arg(delimiter).arg(nick));
   972         isChief = false;
  1025         isChief = false;
   973     }
  1026     }
   974 }
  1027 }
   975 
  1028 
   976 void HWNewNet::consoleCommand(const QString & cmd)
  1029 void HWNewNet::consoleCommand(const QString & cmd)
   977 {
  1030 {
   978     RawSendNet(QString("CMD%1%2").arg(delimeter).arg(cmd));
  1031     RawSendNet(QString("CMD%1%2").arg(delimiter).arg(cmd));
   979 }
  1032 }
   980 
  1033 
   981 bool HWNewNet::allPlayersReady()
  1034 bool HWNewNet::allPlayersReady()
   982 {
  1035 {
   983     int ready = 0;
  1036     int ready = 0;
   992     RawSendNet(QString("START_GAME"));
  1045     RawSendNet(QString("START_GAME"));
   993 }
  1046 }
   994 
  1047 
   995 void HWNewNet::updateRoomName(const QString & name)
  1048 void HWNewNet::updateRoomName(const QString & name)
   996 {
  1049 {
   997     RawSendNet(QString("ROOM_NAME%1%2").arg(delimeter).arg(name));
  1050     RawSendNet(QString("ROOM_NAME%1%2").arg(delimiter).arg(name));
   998 }
  1051 }
   999 
  1052 
  1000 
  1053 
  1001 void HWNewNet::toggleRestrictJoins()
  1054 void HWNewNet::toggleRestrictJoins()
  1002 {
  1055 {
  1030     return netClientState >= InRoom;
  1083     return netClientState >= InRoom;
  1031 }
  1084 }
  1032 
  1085 
  1033 void HWNewNet::setServerMessageNew(const QString & msg)
  1086 void HWNewNet::setServerMessageNew(const QString & msg)
  1034 {
  1087 {
  1035     RawSendNet(QString("SET_SERVER_VAR%1MOTD_NEW%1%2").arg(delimeter).arg(msg));
  1088     RawSendNet(QString("SET_SERVER_VAR%1MOTD_NEW%1%2").arg(delimiter).arg(msg));
  1036 }
  1089 }
  1037 
  1090 
  1038 void HWNewNet::setServerMessageOld(const QString & msg)
  1091 void HWNewNet::setServerMessageOld(const QString & msg)
  1039 {
  1092 {
  1040     RawSendNet(QString("SET_SERVER_VAR%1MOTD_OLD%1%2").arg(delimeter).arg(msg));
  1093     RawSendNet(QString("SET_SERVER_VAR%1MOTD_OLD%1%2").arg(delimiter).arg(msg));
  1041 }
  1094 }
  1042 
  1095 
  1043 void HWNewNet::setLatestProtocolVar(int proto)
  1096 void HWNewNet::setLatestProtocolVar(int proto)
  1044 {
  1097 {
  1045     RawSendNet(QString("SET_SERVER_VAR%1LATEST_PROTO%1%2").arg(delimeter).arg(proto));
  1098     RawSendNet(QString("SET_SERVER_VAR%1LATEST_PROTO%1%2").arg(delimiter).arg(proto));
  1046 }
  1099 }
  1047 
  1100 
  1048 void HWNewNet::askServerVars()
  1101 void HWNewNet::askServerVars()
  1049 {
  1102 {
  1050     RawSendNet(QString("GET_SERVER_VAR"));
  1103     RawSendNet(QString("GET_SERVER_VAR"));
  1081 void HWNewNet::roomPasswordEntered(const QString &password)
  1134 void HWNewNet::roomPasswordEntered(const QString &password)
  1082 {
  1135 {
  1083     if(!myroom.isEmpty())
  1136     if(!myroom.isEmpty())
  1084         JoinRoom(myroom, password);
  1137         JoinRoom(myroom, password);
  1085 }
  1138 }
       
  1139 
       
  1140 void HWNewNet::maybeSendPassword()
       
  1141 {
       
  1142 /* When we got password hash, and server asked us for a password, perform mutual authentication:
       
  1143  * at this point we have salt chosen by server
       
  1144  * client sends client salt and hash of secret (password hash) salted with client salt, server salt,
       
  1145  * and static salt (predefined string + protocol number)
       
  1146  * server should respond with hash of the same set in different order.
       
  1147  */
       
  1148 
       
  1149     if(m_passwordHash.isEmpty() || m_serverSalt.isEmpty())
       
  1150         return;
       
  1151 
       
  1152     QString hash = QCryptographicHash::hash(
       
  1153                 m_clientSalt.toAscii()
       
  1154                 .append(m_serverSalt.toAscii())
       
  1155                 .append(m_passwordHash)
       
  1156                 .append(cProtoVer->toAscii())
       
  1157                 .append("!hedgewars")
       
  1158                 , QCryptographicHash::Sha1).toHex();
       
  1159 
       
  1160     m_serverHash = QCryptographicHash::hash(
       
  1161                 m_serverSalt.toAscii()
       
  1162                 .append(m_clientSalt.toAscii())
       
  1163                 .append(m_passwordHash)
       
  1164                 .append(cProtoVer->toAscii())
       
  1165                 .append("!hedgewars")
       
  1166                 , QCryptographicHash::Sha1).toHex();
       
  1167 
       
  1168     RawSendNet(QString("PASSWORD%1%2%1%3").arg(delimiter).arg(hash).arg(m_clientSalt));
       
  1169 }