Toni Förster has proposed merging lp:~widelands-dev/widelands/bug-1797702-spaces-in-names into lp:widelands.
Commit message: rework netsetup - allowed characters are limited - login with empty username not allowed - if username ist taken append number - don't join game with empty username editbox - added has_warning() Requested reviews: Widelands Developers (widelands-dev) Related bugs: Bug #1797702 in widelands: "Player names in chat commands can't contain whitespace" https://bugs.launchpad.net/widelands/+bug/1797702 For more details, see: https://code.launchpad.net/~widelands-dev/widelands/bug-1797702-spaces-in-names/+merge/367122 -- Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1797702-spaces-in-names into lp:widelands.
=== modified file 'src/network/gamehost.cc' --- src/network/gamehost.cc 2019-04-29 16:22:08 +0000 +++ src/network/gamehost.cc 2019-05-08 15:04:09 +0000 @@ -1621,13 +1621,13 @@ // Assign the player a name, preferably the name chosen by the client if (playername.empty()) // Make sure there is at least a name base. - playername = _("Player"); + playername = "Player"; std::string effective_name = playername; if (has_user_name(effective_name, client.usernum)) { - uint32_t i = 2; + uint32_t i = 1; do { - effective_name = (boost::format(_("Player %u")) % i++).str(); + effective_name = (boost::format("%s%u") % playername % i++).str(); } while (has_user_name(effective_name, client.usernum)); } === modified file 'src/network/internet_gaming.cc' --- src/network/internet_gaming.cc 2019-05-05 22:50:03 +0000 +++ src/network/internet_gaming.cc 2019-05-08 15:04:09 +0000 @@ -487,7 +487,7 @@ InternetGame* ing = new InternetGame(); ing->name = packet.string(); ing->build_id = packet.string(); - ing->connectable = (packet.string() == INTERNET_GAME_SETUP); + ing->connectable = packet.string(); gamelist_.push_back(*ing); bool found = false; @@ -498,10 +498,13 @@ break; } } - if (!found) + if (!found && ing->connectable != INTERNET_GAME_RUNNING && + (ing->build_id == build_id() || (ing->build_id.compare(0, 6, "build-") != 0 + && build_id().compare(0, 6, "build-") != 0))) { format_and_add_chat( - "", "", true, - (boost::format(_("The game %s is now available")) % ing->name).str()); + "", "", true, + (boost::format(_("The game %s is now available")) % ing->name).str()); + } delete ing; ing = nullptr; === modified file 'src/network/internet_gaming.h' --- src/network/internet_gaming.h 2019-02-23 11:00:49 +0000 +++ src/network/internet_gaming.h 2019-05-08 15:04:09 +0000 @@ -43,7 +43,7 @@ struct InternetGame { std::string name; std::string build_id; - bool connectable; + std::string connectable; }; /** @@ -178,6 +178,11 @@ return true; } + void format_and_add_chat(const std::string& from, + const std::string& to, + bool system, + const std::string& msg); + private: InternetGaming(); @@ -202,11 +207,6 @@ bool str2bool(std::string); std::string bool2str(bool); - void format_and_add_chat(const std::string& from, - const std::string& to, - bool system, - const std::string& msg); - /** * Does the real work of the login. * \param relogin Whether this is a relogin. Only difference is that === modified file 'src/ui_basic/editbox.cc' --- src/ui_basic/editbox.cc 2019-04-09 16:43:49 +0000 +++ src/ui_basic/editbox.cc 2019-05-08 15:04:09 +0000 @@ -85,7 +85,8 @@ : Panel(parent, x, y, w, h > 0 ? h : text_height(font_size) + 2 * margin_y), m_(new EditBoxImpl), history_active_(false), - history_position_(-1) { + history_position_(-1), + warning_(false) { set_thinks(false); m_->background_style = g_gr->styles().editbox_style(style); @@ -346,7 +347,7 @@ draw_background(dst, *m_->background_style); // Draw border. - if (get_w() >= 2 && get_h() >= 2) { + if (get_w() >= 2 && get_h() >= 2 && !warning_) { static const RGBColor black(0, 0, 0); // bottom edge @@ -359,6 +360,25 @@ // left edge dst.fill_rect(Recti(0, 0, 1, get_h() - 1), black); dst.fill_rect(Recti(1, 0, 1, get_h() - 2), black); + + } else { + // Draw a red border for warnings. + static const RGBColor red(255, 22, 22); + + // bottom edge + dst.fill_rect(Recti(0, get_h() - 2, get_w(), 2), red); + // right edge + dst.fill_rect(Recti(get_w() - 2, 0, 2, get_h() -2), red); + // top edge + dst.fill_rect(Recti(0, 0, get_w() - 1, 1), red); + dst.fill_rect(Recti(0, 1, get_w() - 2, 1), red); + dst.brighten_rect(Recti(0, 0, get_w() - 1, 1), BUTTON_EDGE_BRIGHT_FACTOR); + dst.brighten_rect(Recti(0, 1, get_w() - 2, 1), BUTTON_EDGE_BRIGHT_FACTOR); + // left edge + dst.fill_rect(Recti(0, 0, 1, get_h() - 1), red); + dst.fill_rect(Recti(1, 0, 1, get_h() - 2), red); + dst.brighten_rect(Recti(0, 0, 1, get_h() - 1), BUTTON_EDGE_BRIGHT_FACTOR); + dst.brighten_rect(Recti(1, 0, 1, get_h() - 2), BUTTON_EDGE_BRIGHT_FACTOR); } if (has_focus()) { === modified file 'src/ui_basic/editbox.h' --- src/ui_basic/editbox.h 2019-02-23 11:00:49 +0000 +++ src/ui_basic/editbox.h 2019-05-08 15:04:09 +0000 @@ -72,6 +72,14 @@ void draw(RenderTarget&) override; + void set_warning(bool warn) { + warning_ = warn; + } + + bool has_warning() { + return warning_; + } + private: std::unique_ptr<EditBoxImpl> m_; @@ -80,6 +88,7 @@ bool history_active_; int16_t history_position_; std::string history_[CHAT_HISTORY_SIZE]; + bool warning_; }; } // namespace UI === modified file 'src/ui_fsmenu/internet_lobby.cc' --- src/ui_fsmenu/internet_lobby.cc 2019-05-05 00:22:27 +0000 +++ src/ui_fsmenu/internet_lobby.cc 2019-05-08 15:04:09 +0000 @@ -63,7 +63,7 @@ // Text labels title(this, get_w() / 2, get_h() / 20, _("Metaserver Lobby"), UI::Align::kCenter), clients_(this, get_w() * 4 / 125, get_h() * 15 / 100, _("Clients online:")), - opengames_(this, get_w() * 17 / 25, get_h() * 15 / 100, _("List of games:")), + opengames_(this, get_w() * 17 / 25, get_h() * 15 / 100, _("Open Games:")), servername_(this, get_w() * 17 / 25, get_h() * 63 / 100, _("Name of your server:")), // Buttons @@ -223,28 +223,37 @@ // List and button cleanup opengames_list_.clear(); hostgame_.set_enabled(true); + edit_servername_.set_tooltip(""); + edit_servername_.set_warning(false); joingame_.set_enabled(false); std::string localservername = edit_servername_.text(); + std::string localbuildid = build_id(); if (games != nullptr) { // If no communication error occurred, fill the list. for (const InternetGame& game : *games) { const Image* pic; - if (game.connectable) { - if (game.build_id == build_id()) - pic = g_gr->images().get("images/ui_basic/continue.png"); - else { + if (game.connectable == INTERNET_GAME_SETUP && game.build_id == localbuildid) { + // only clients with the same build number are displayed + pic = g_gr->images().get("images/ui_basic/continue.png"); + opengames_list_.add(game.name, game, pic, false, game.build_id); + } else if (game.connectable == INTERNET_GAME_SETUP && + game.build_id.compare(0, 6, "build-") != 0 && + localbuildid.compare(0, 6, "build-") != 0) { + // only development clients are allowed to see games openend by such pic = g_gr->images().get("images/ui_basic/different.png"); - } - } else { - pic = g_gr->images().get("images/ui_basic/stop.png"); + opengames_list_.add(game.name, game, pic, false, game.build_id); } // If one of the servers has the same name as the local name of the // clients server, we disable the 'hostgame' button to avoid having more // than one server with the same name. if (game.name == localservername) { hostgame_.set_enabled(false); + edit_servername_.set_warning(true); + edit_servername_.set_tooltip( + (boost::format("%s%s%s%s%s%s%s%s") % _("The game ") % "<font bold=yes color=" + % UI_FONT_CLR_WARNING.hex_value() % ">" % game.name % "</font>" + % _(" is already running. ") % _("Please choose a different name.")).str()); } - opengames_list_.add(game.name, game, pic, false, game.build_id); } } } @@ -341,10 +350,8 @@ // remove focus from chat if (opengames_list_.has_selection()) { const InternetGame* game = &opengames_list_.get_selected(); - if (game->connectable) + if (game->connectable == INTERNET_GAME_SETUP) joingame_.set_enabled(true); - else - joingame_.set_enabled(false); } } @@ -353,7 +360,7 @@ // if the game is open try to connect it, if not do nothing. if (opengames_list_.has_selection()) { const InternetGame* game = &opengames_list_.get_selected(); - if (game->connectable) + if (game->connectable == INTERNET_GAME_SETUP) clicked_joingame(); } } @@ -362,7 +369,8 @@ void FullscreenMenuInternetLobby::change_servername() { // Allow client to enter a servername manually hostgame_.set_enabled(true); - + edit_servername_.set_tooltip(""); + edit_servername_.set_warning(false); // Check whether a server of that name is already open. // And disable 'hostgame' button if yes. const std::vector<InternetGame>* games = InternetGaming::ref().games(); @@ -370,6 +378,11 @@ for (const InternetGame& game : *games) { if (game.name == edit_servername_.text()) { hostgame_.set_enabled(false); + edit_servername_.set_warning(true); + edit_servername_.set_tooltip( + (boost::format("%s%s%s%s%s%s%s%s") % _("The game ") % "<font bold=yes color=" + % UI_FONT_CLR_WARNING.hex_value() % ">" % game.name % "</font>" + % _(" is already running. ") % _("Please choose a different name.")).str()); } } } === modified file 'src/ui_fsmenu/multiplayer.cc' --- src/ui_fsmenu/multiplayer.cc 2019-02-23 11:00:49 +0000 +++ src/ui_fsmenu/multiplayer.cc 2019-05-08 15:04:09 +0000 @@ -58,21 +58,46 @@ vbox_.add_inf_space(); vbox_.add(&back, UI::Box::Resizing::kFullSize); - Section& s = g_options.pull_section("global"); - auto_log_ = s.get_bool("auto_log", false); - if (auto_log_) { - showloginbox = + showloginbox = new UI::Button(this, "login_dialog", 0, 0, 0, 0, UI::ButtonStyle::kFsMenuSecondary, g_gr->images().get("images/ui_basic/continue.png"), _("Show login dialog")); - showloginbox->sigclicked.connect( + showloginbox->sigclicked.connect( boost::bind(&FullscreenMenuMultiPlayer::show_internet_login, boost::ref(*this))); - } layout(); } /// called if the showloginbox button was pressed void FullscreenMenuMultiPlayer::show_internet_login() { - auto_log_ = false; + Section& s = g_options.pull_section("global"); + LoginBox lb(*this); + if (lb.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) { + nickname_ = lb.get_nickname(); + s.set_string("nickname", nickname_); + /// NOTE: The password is only stored (in memory and on disk) and transmitted (over the + /// network + /// to the metaserver) as cryptographic hash. This does NOT mean that the password is + /// stored + /// securely on the local disk. While the password should be secure while transmitted to + /// the + /// metaserver (no-one can use the transmitted data to log in as the user) this is not the + /// case + /// for local storage. The stored hash of the password makes it hard to look at the + /// configuration + /// file and figure out the plaintext password to, e.g., log in on the forum. However, the + /// stored hash can be copied to another system and used to log in as the user on the + /// metaserver. + // Further note: SHA-1 is considered broken and shouldn't be used anymore. But since the + // passwords on the server are protected by SHA-1 we have to use it here, too + if (lb.get_password() != "*****") { + password_ = crypto::sha1(lb.get_password()); + s.set_string("password_sha1", password_); + } + + register_ = lb.registered(); + s.set_bool("registered", lb.registered()); + } else { + return; + } internet_login(); } @@ -90,37 +115,14 @@ */ void FullscreenMenuMultiPlayer::internet_login() { Section& s = g_options.pull_section("global"); - if (auto_log_) { - nickname_ = s.get_string("nickname", _("nobody")); - password_ = s.get_string("password_sha1", "nobody"); - register_ = s.get_bool("registered", false); - } else { - LoginBox lb(*this); - if (lb.run<UI::Panel::Returncodes>() == UI::Panel::Returncodes::kOk) { - nickname_ = lb.get_nickname(); - /// NOTE: The password is only stored (in memory and on disk) and transmitted (over the - /// network - /// to the metaserver) as cryptographic hash. This does NOT mean that the password is - /// stored - /// securely on the local disk. While the password should be secure while transmitted to - /// the - /// metaserver (no-one can use the transmitted data to log in as the user) this is not the - /// case - /// for local storage. The stored hash of the password makes it hard to look at the - /// configuration - /// file and figure out the plaintext password to, e.g., log in on the forum. However, the - /// stored hash can be copied to another system and used to log in as the user on the - /// metaserver. - // Further note: SHA-1 is considered broken and shouldn't be used anymore. But since the - // passwords on the server are protected by SHA-1 we have to use it here, too - password_ = crypto::sha1(lb.get_password()); - register_ = lb.registered(); - - s.set_bool("registered", lb.registered()); - s.set_bool("auto_log", lb.set_automaticlog()); - } else { - return; - } + + nickname_ = s.get_string("nickname", _(" ")); + password_ = s.get_string("password_sha1", "nobody"); + register_ = s.get_bool("registered", false); + + if (nickname_ == " ") { + show_internet_login(); + return; } // Try to connect to the metaserver === modified file 'src/ui_fsmenu/multiplayer.h' --- src/ui_fsmenu/multiplayer.h 2019-02-23 11:00:49 +0000 +++ src/ui_fsmenu/multiplayer.h 2019-05-08 15:04:09 +0000 @@ -61,7 +61,6 @@ std::string nickname_; std::string password_; bool register_; - bool auto_log_; }; #endif // end of include guard: WL_UI_FSMENU_MULTIPLAYER_H === modified file 'src/ui_fsmenu/netsetup_lan.cc' --- src/ui_fsmenu/netsetup_lan.cc 2019-04-09 16:43:49 +0000 +++ src/ui_fsmenu/netsetup_lan.cc 2019-05-08 15:04:09 +0000 @@ -136,6 +136,7 @@ void FullscreenMenuNetSetupLAN::think() { FullscreenMenuBase::think(); + change_playername(); discovery.run(); } @@ -186,7 +187,7 @@ assert(opengames.has_selection()); const NetOpenGame* const game = opengames.get_selected(); // Only join games that are open - if (game->info.state == LAN_GAME_OPEN) { + if (game->info.state == LAN_GAME_OPEN || !playername.has_warning()) { clicked_joingame(); } } @@ -247,6 +248,24 @@ } void FullscreenMenuNetSetupLAN::change_playername() { + playername.set_warning(false); + playername.set_tooltip(""); + hostgame.set_enabled(true); + + if (playername.text().find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@.+-_") <= playername.text().size() + || playername.text().empty()) { + playername.set_warning(true); + playername.set_tooltip(_("Enter a valid nickname. This value may contain only " + "English letters, numbers, and @ . + - _ characters.")); + joingame.set_enabled(false); + hostgame.set_enabled(false); + return; + } + if (!hostname.text().empty()) { + joingame.set_enabled(true); + } + g_options.pull_section("global").set_string("nickname", playername.text()); } === modified file 'src/wui/login_box.cc' --- src/wui/login_box.cc 2019-02-23 11:00:49 +0000 +++ src/wui/login_box.cc 2019-05-08 15:04:09 +0000 @@ -26,7 +26,7 @@ #include "ui_basic/messagebox.h" LoginBox::LoginBox(Panel& parent) - : Window(&parent, "login_box", 0, 0, 500, 220, _("Metaserver login")) { + : Window(&parent, "login_box", 0, 0, 500, 260, _("Metaserver login")) { center_to_parent(); int32_t margin = 10; @@ -36,59 +36,53 @@ eb_nickname = new UI::EditBox(this, 150, margin, 330, 20, 2, UI::PanelStyle::kWui); eb_password = new UI::EditBox(this, 150, 40, 330, 20, 2, UI::PanelStyle::kWui); - pwd_warning = - new UI::MultilineTextarea(this, margin, 65, 505, 50, UI::PanelStyle::kWui, - _("WARNING: Password will be shown and saved readable!")); - - cb_register = new UI::Checkbox(this, Vector2i(margin, 110), _("Log in to a registered account"), + cb_register = new UI::Checkbox(this, Vector2i(margin, 70), _("Log in to a registered account"), "", get_inner_w() - 2 * margin); - cb_auto_log = new UI::Checkbox(this, Vector2i(margin, 135), - _("Automatically use this login information from now on."), "", - get_inner_w() - 2 * margin); - - UI::Button* loginbtn = new UI::Button( + + register_account = new UI::MultilineTextarea(this, margin, 105, 470, 140, UI::PanelStyle::kWui, + _("To register an account, please visit our website: \n\n" + "https://widelands.org/accounts/register/ \n\n" + "Log in to your newly created account and set an \n" + "online gaming password on your profile page.")); + + loginbtn = new UI::Button( this, "login", UI::g_fh->fontset()->is_rtl() ? (get_inner_w() / 2 - 200) / 2 : (get_inner_w() / 2 - 200) / 2 + get_inner_w() / 2, get_inner_h() - 20 - margin, 200, 20, UI::ButtonStyle::kWuiPrimary, _("Login")); - loginbtn->sigclicked.connect(boost::bind(&LoginBox::clicked_ok, boost::ref(*this))); - UI::Button* cancelbtn = new UI::Button( + + cancelbtn = new UI::Button( this, "cancel", UI::g_fh->fontset()->is_rtl() ? (get_inner_w() / 2 - 200) / 2 + get_inner_w() / 2 : (get_inner_w() / 2 - 200) / 2, loginbtn->get_y(), 200, 20, UI::ButtonStyle::kWuiSecondary, _("Cancel")); + + loginbtn->sigclicked.connect(boost::bind(&LoginBox::clicked_ok, boost::ref(*this))); cancelbtn->sigclicked.connect(boost::bind(&LoginBox::clicked_back, boost::ref(*this))); + eb_nickname->changed.connect(boost::bind(&LoginBox::change_playername, this)); Section& s = g_options.pull_section("global"); eb_nickname->set_text(s.get_string("nickname", _("nobody"))); cb_register->set_state(s.get_bool("registered", false)); + + if (registered()) { + eb_password->set_text("*****"); + } else { + eb_password->set_can_focus(false); + } + eb_nickname->focus(); } +/// think function of the UI (main loop) +void LoginBox::think() { + verify_input(); +} + /** * called, if "login" is pressed. */ void LoginBox::clicked_ok() { - // Check if all needed input fields are valid - if (eb_nickname->text().empty()) { - UI::WLMessageBox mb( - this, _("Empty Nickname"), _("Please enter a nickname!"), UI::WLMessageBox::MBoxType::kOk); - mb.run<UI::Panel::Returncodes>(); - return; - } - if (eb_nickname->text().find(' ') <= eb_nickname->text().size()) { - UI::WLMessageBox mb(this, _("Space in Nickname"), - _("Sorry, but spaces are not allowed in nicknames!"), - UI::WLMessageBox::MBoxType::kOk); - mb.run<UI::Panel::Returncodes>(); - return; - } - if (eb_password->text().empty() && cb_register->get_state()) { - UI::WLMessageBox mb(this, _("Empty Password"), _("Please enter your password!"), - UI::WLMessageBox::MBoxType::kOk); - mb.run<UI::Panel::Returncodes>(); - return; - } end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kOk); } @@ -97,6 +91,11 @@ end_modal<UI::Panel::Returncodes>(UI::Panel::Returncodes::kBack); } +/// Calles when nickname was changed +void LoginBox::change_playername() { + cb_register->set_state(false); +} + bool LoginBox::handle_key(bool down, SDL_Keysym code) { if (down) { switch (code.sym) { @@ -113,3 +112,43 @@ } return UI::Panel::handle_key(down, code); } + +void LoginBox::verify_input() { + // Check if all needed input fields are valid + loginbtn->set_enabled(true); + eb_nickname->set_tooltip(""); + eb_password->set_tooltip(""); + eb_nickname->set_warning(false); + eb_password->set_warning(false); + + if (eb_nickname->text().empty()) { + eb_nickname->set_warning(true); + eb_nickname->set_tooltip(_("Please enter a nickname!")); + loginbtn->set_enabled(false); + } + + if (eb_nickname->text().find_first_not_of("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@.+-_") <= eb_nickname->text().size()) { + eb_nickname->set_warning(true); + eb_nickname->set_tooltip(_("Enter a valid nickname. This value may contain only " + "English letters, numbers, and @ . + - _ characters.")); + loginbtn->set_enabled(false); + + } + + if (eb_password->text().empty() && cb_register->get_state()) { + eb_password->set_warning(true); + eb_password->set_tooltip(_("Please enter your password!")); + eb_password->focus(); + loginbtn->set_enabled(false); + } + + if (!eb_password->text().empty() && !cb_register->get_state()) { + eb_password->set_text(""); + eb_password->set_can_focus(false); + } + + if (eb_password->has_focus() && eb_password->text() == "*****") { + eb_password->set_text(""); + } +} === modified file 'src/wui/login_box.h' --- src/wui/login_box.h 2019-02-23 11:00:49 +0000 +++ src/wui/login_box.h 2019-05-08 15:04:09 +0000 @@ -29,6 +29,10 @@ struct LoginBox : public UI::Window { explicit LoginBox(UI::Panel&); + void think() override; + + void verify_input(); + std::string get_nickname() { return eb_nickname->text(); } @@ -38,9 +42,6 @@ bool registered() { return cb_register->get_state(); } - bool set_automaticlog() { - return cb_auto_log->get_state(); - } /// Handle keypresses bool handle_key(bool down, SDL_Keysym code) override; @@ -48,14 +49,16 @@ private: void clicked_back(); void clicked_ok(); + void change_playername(); + UI::Button* loginbtn; + UI::Button* cancelbtn; UI::EditBox* eb_nickname; UI::EditBox* eb_password; UI::Checkbox* cb_register; - UI::Checkbox* cb_auto_log; UI::Textarea* ta_nickname; UI::Textarea* ta_password; - UI::MultilineTextarea* pwd_warning; + UI::MultilineTextarea* register_account; }; #endif // end of include guard: WL_WUI_LOGIN_BOX_H
_______________________________________________ Mailing list: https://launchpad.net/~widelands-dev Post to : widelands-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~widelands-dev More help : https://help.launchpad.net/ListHelp