/** * Compare two string. */ int string_compare(const string_t* cpstr_first, const string_t* cpstr_second) { return string_compare_cstr(cpstr_first, string_c_str(cpstr_second)); }
static void login_trilogy_handle_op_server_list(LoginClient* client, ProtocolHandler* handler) { Login* login; ServerList* list; ServerListing* data; PacketTrilogy* packet; Aligned write; Aligned* w = &write; uint32_t count; uint32_t length; uint32_t n; uint32_t i; uint32_t ip; bool isLocal; char address[INET_ADDRSTRLEN]; if (login_client_get_state(client) != LoginClientTrilogy_AcceptedCredentials) return; isLocal = login_client_is_local(client); login = (Login*)protocol_handler_basic(handler); list = login_server_list(login); count = server_list_count(list); ip = protocol_handler_ip_address(handler)->sin_addr.s_addr; snprintf(address, sizeof(address), "%u.%u.%u.%u", (ip >> 0) & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff); // Figure out how long the packet will be data = server_list_data(list); length = sizeof(LoginTrilogy_ServerListHeader) + sizeof(LoginTrilogy_ServerListFooter); n = 0; for (i = 0; i < count; i++) { ServerListing* server = &data[i]; if (!server_listing_name(server)) continue; /* There are two different 'local address' cases to handle: 1) Login, char-select and client are all local to each other; or 2) Char-select and client are local to each other, but both are remote to login In the first case, both char-select and client will have been flagged as local (to the login server) and the client's address will not match the remote address for char-select. In the second case, neither char-select and client will have been flagged as local, but the client's address will (presumably, and typically) be the same as char-select's remote address. */ if ((isLocal && server_listing_is_local(server)) || string_compare_cstr(server_listing_remote_address(server), address)) length += string_length(server_listing_local_address(server)) + 1; else length += server_listing_remote_length(server); length += server_listing_name_length(server); length += sizeof(LoginTrilogy_ServerFooter); if (++n == SERVER_LIST_COUNT_MAX) break; } // Create and fill the packet packet = packet_trilogy_create(B(login), TrilogyOp_ServerList, length); aligned_init(B(login), w, packet_trilogy_data(packet), packet_trilogy_length(packet)); /* ServerListHeader */ // serverCount aligned_write_uint8(w, n); // unknown (2 bytes) aligned_write_zeroes(w, sizeof(uint8_t) * 2); // showNumPlayers aligned_write_uint8(w, 0xff); // Show actual numbers rather than just "Up" /* Server entries and footers */ n = 0; for (i = 0; i < count; i++) { int playerCount; ServerListing* server = &data[i]; if (!server_listing_name(server)) continue; switch (server_listing_status(server)) { case ServerStatus_Down: playerCount = SERVER_DOWN; break; case ServerStatus_Locked: playerCount = SERVER_LOCKED; break; default: playerCount = server_listing_player_count(server); break; } // server name aligned_write_string_null_terminated(w, server_listing_name(server)); // ip address if ((isLocal && server_listing_is_local(server)) || string_compare_cstr(server_listing_remote_address(server), address)) aligned_write_string_null_terminated(w, server_listing_local_address(server)); else aligned_write_string_null_terminated(w, server_listing_remote_address(server)); // isGreenName aligned_write_bool(w, (server_listing_rank(server) != ServerRank_Standard)); // playerCount aligned_write_int32(w, playerCount); if (++n == SERVER_LIST_COUNT_MAX) break; } /* ServerListFooter */ // admin aligned_write_uint8(w, 0); // zeroes A (8 bytes) aligned_write_zeroes(w, sizeof(uint8_t) * 8); // kunark aligned_write_uint8(w, 1); // velious aligned_write_uint8(w, 1); // zeroes B (12 bytes) aligned_write_zeroes(w, sizeof(uint8_t) * 12); login_trilogy_schedule_packet(handler, packet); }