/*
Minetest
Copyright (C) 2015 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "client/client.h"
#include "util/base64.h"
#include "client/camera.h"
#include "chatmessage.h"
#include "client/clientmedia.h"
#include "log.h"
#include "map.h"
#include "mapsector.h"
#include "client/minimap.h"
#include "modchannels.h"
#include "nodedef.h"
#include "serialization.h"
#include "server.h"
#include "util/strfnd.h"
#include "client/clientevent.h"
#include "client/sound.h"
#include "network/clientopcodes.h"
#include "network/connection.h"
#include "script/scripting_client.h"
#include "util/serialize.h"
#include "util/srp.h"
#include "util/sha1.h"
#include "tileanimation.h"
#include "gettext.h"
#include "skyparams.h"
void Client::handleCommand_Deprecated(NetworkPacket* pkt)
{
infostream << "Got deprecated command "
<< toClientCommandTable[pkt->getCommand()].name << " from peer "
<< pkt->getPeerId() << "!" << std::endl;
}
void Client::handleCommand_Hello(NetworkPacket* pkt)
{
if (pkt->getSize() < 1)
return;
u8 serialization_ver;
u16 proto_ver;
u16 compression_mode;
u32 auth_mechs;
std::string username_legacy; // for case insensitivity
*pkt >> serialization_ver >> compression_mode >> proto_ver
>> auth_mechs >> username_legacy;
// Chose an auth method we support
AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);
infostream << "Client: TOCLIENT_HELLO received with "
<< "serialization_ver=" << (u32)serialization_ver
<< ", auth_mechs=" << auth_mechs
<< ", proto_ver=" << proto_ver
<< ", compression_mode=" << compression_mode
<< ". Doing auth with mech " << chosen_auth_mechanism << std::endl;
if (!ser_ver_supported(serialization_ver)) {
infostream << "Client: TOCLIENT_HELLO: Server sent "
<< "unsupported ser_fmt_ver"<< std::endl;
return;
}
m_server_ser_ver = serialization_ver;
m_proto_ver = proto_ver;
//TODO verify that username_legacy matches sent username, only
// differs in casing (make both uppercase and compare)
// This is only neccessary though when we actually want to add casing support
if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
// we recieved a TOCLIENT_HELLO while auth was already going on
errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
<< "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
if (m_chosen_auth_mech == AUTH_MECHANISM_SRP ||
m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD) {
srp_user_delete((SRPUser *) m_auth_data);
m_auth_data = 0;
}
}
// Authenticate using that method, or abort if there wasn't any method found
if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
if (chosen_auth_mechanism == AUTH_MECHANISM_FIRST_SRP &&
!m_simple_singleplayer_mode &&
!getServerAddress().isLocalhost() &&
g_settings->getBool("enable_register_confirmation")) {
promptConfirmRegistration(chosen_auth_mechanism);
} else {
startAuth(chosen_auth_mechanism);
}
} else {
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
m_access_denied = true;
m_access_denied_reason = "Unknown";
m_con->Disconnect();
}
}
void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
{
deleteAuthData();
v3f playerpos;
*pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
>> m_sudo_auth_methods;
playerpos -= v3f(0, BS / 2, 0);
// Set player position
LocalPlayer *player = m_env.getLocalPlayer();
assert(player != NULL);
player->setPosition(playerpos);
infostream << "Client: received map seed: " << m_map_seed << std::endl;
infostream << "Client: received recommended send interval "
<< m_recommended_send_interval<<std::endl;
// Reply to server
/*~ DO NOT TRANSLATE THIS LITERALLY!
This is a special string which needs to contain the translation's
language code (e.g. "de" for German). */
std::string lang = gettext("LANG_CODE");
if (lang == "LANG_CODE")
lang = "";
NetworkPacket resp_pkt(TOSERVER_INIT2, sizeof(u16) + lang.size());
resp_pkt << lang;
Send(&resp_pkt);
m_state = LC_Init;
}
void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
{
deleteAuthData();
m_password = m_new_password;
verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;
// send packet to actually set the password
startAuth(AUTH_MECHANISM_FIRST_SRP);
// reset again
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
}
void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
{
ChatMessage *chatMessage = new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
L"Password change denied. Password NOT changed.");
pushToChatQueue(chatMessage);
// reset everything and be sad
deleteAuthData();
}
void Client::handleCommand_AccessDenied(NetworkPacket* pkt)
{
// The server didn't like our password. Note, this needs
// to be processed even if the serialisation format has
|