diff --git a/include/ui/auth_screen.hpp b/include/ui/auth_screen.hpp index e8630b3f..ef11ed94 100644 --- a/include/ui/auth_screen.hpp +++ b/include/ui/auth_screen.hpp @@ -70,6 +70,14 @@ private: * Update status message */ void setStatus(const std::string& message, bool isError = false); + + /** + * Persist/restore login fields + */ + void saveLoginInfo(); + void loadLoginInfo(); + static std::string getConfigPath(); + bool loginInfoLoaded = false; }; }} // namespace wowee::ui diff --git a/src/network/tcp_socket.cpp b/src/network/tcp_socket.cpp index 93fb212b..15380bfa 100644 --- a/src/network/tcp_socket.cpp +++ b/src/network/tcp_socket.cpp @@ -52,6 +52,34 @@ bool TCPSocket::connect(const std::string& host, uint16_t port) { sockfd = INVALID_SOCK; return false; } + + // Non-blocking connect in progress — wait for it to complete + fd_set writefds; + FD_ZERO(&writefds); + FD_SET(sockfd, &writefds); + + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + + int selectResult = ::select(static_cast(sockfd) + 1, nullptr, &writefds, nullptr, &tv); + if (selectResult <= 0) { + LOG_ERROR("Connection timed out to ", host, ":", port); + net::closeSocket(sockfd); + sockfd = INVALID_SOCK; + return false; + } + + // Check if the connection actually succeeded + int sockErr = 0; + socklen_t errLen = sizeof(sockErr); + getsockopt(sockfd, SOL_SOCKET, SO_ERROR, reinterpret_cast(&sockErr), &errLen); + if (sockErr != 0) { + LOG_ERROR("Connection failed: ", net::errorString(sockErr)); + net::closeSocket(sockfd); + sockfd = INVALID_SOCK; + return false; + } } connected = true; diff --git a/src/ui/auth_screen.cpp b/src/ui/auth_screen.cpp index 774ba888..f3f804b4 100644 --- a/src/ui/auth_screen.cpp +++ b/src/ui/auth_screen.cpp @@ -1,6 +1,10 @@ #include "ui/auth_screen.hpp" +#include "core/logger.hpp" #include #include +#include +#include +#include namespace wowee { namespace ui { @@ -8,6 +12,12 @@ AuthScreen::AuthScreen() { } void AuthScreen::render(auth::AuthHandler& authHandler) { + // Load saved login info on first render + if (!loginInfoLoaded) { + loadLoginInfo(); + loginInfoLoaded = true; + } + ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); ImGui::Begin("WoW 3.3.5a Authentication", nullptr, ImGuiWindowFlags_NoCollapse); @@ -155,6 +165,9 @@ void AuthScreen::attemptAuth(auth::AuthHandler& authHandler) { authTimer = 0.0f; setStatus("Connected, authenticating...", false); + // Save login info for next session + saveLoginInfo(); + // Send authentication credentials authHandler.authenticate(username, password); } else { @@ -170,4 +183,61 @@ void AuthScreen::setStatus(const std::string& message, bool isError) { statusIsError = isError; } +std::string AuthScreen::getConfigPath() { + std::string dir; +#ifdef _WIN32 + const char* appdata = std::getenv("APPDATA"); + dir = appdata ? std::string(appdata) + "\\wowee" : "."; +#else + const char* home = std::getenv("HOME"); + dir = home ? std::string(home) + "/.wowee" : "."; +#endif + return dir + "/login.cfg"; +} + +void AuthScreen::saveLoginInfo() { + std::string path = getConfigPath(); + std::filesystem::path dir = std::filesystem::path(path).parent_path(); + std::error_code ec; + std::filesystem::create_directories(dir, ec); + + std::ofstream out(path); + if (!out.is_open()) { + LOG_WARNING("Could not save login info to ", path); + return; + } + + out << "hostname=" << hostname << "\n"; + out << "port=" << port << "\n"; + out << "username=" << username << "\n"; + + LOG_INFO("Login info saved to ", path); +} + +void AuthScreen::loadLoginInfo() { + std::string path = getConfigPath(); + std::ifstream in(path); + if (!in.is_open()) return; + + std::string line; + while (std::getline(in, line)) { + size_t eq = line.find('='); + if (eq == std::string::npos) continue; + std::string key = line.substr(0, eq); + std::string val = line.substr(eq + 1); + + if (key == "hostname" && !val.empty()) { + strncpy(hostname, val.c_str(), sizeof(hostname) - 1); + hostname[sizeof(hostname) - 1] = '\0'; + } else if (key == "port") { + try { port = std::stoi(val); } catch (...) {} + } else if (key == "username" && !val.empty()) { + strncpy(username, val.c_str(), sizeof(username) - 1); + username[sizeof(username) - 1] = '\0'; + } + } + + LOG_INFO("Login info loaded from ", path); +} + }} // namespace wowee::ui