bool fs2netd_login()
{
	bool retval = true;
	int rc;

	// don't bother with this if we aren't on FS2NetD
	if ( !Om_tracker_flag ) {
		return false;
	}

	if ( !(Game_mode & GM_MULTIPLAYER) ) {
		return false;
	}

	if ( Logged_in && (Multi_tracker_id >= 0) ) {
		return true;
	}

	Logged_in = false;

	Multi_tracker_id = -1;
	memset( Multi_tracker_id_string, 0, sizeof(Multi_tracker_id_string) );

	// verify that our connection settings are sane
	fs2netd_options_config_init();

	// if we're a standalone, show a dialog saying "validating tables"
	if (Is_standalone) {
		std_create_gen_dialog("Logging into FS2NetD");
		std_gen_set_text("Connecting...", 1);
	}

	fs2netd_connect();

	if ( !Is_connected ) {
		if ( !Is_standalone ) {
			popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Failed to connect to FS2NetD server!", 1578));
		} else {
			std_gen_set_text("Connect FAILED!", 1);
			Sleep(2000);
			std_destroy_gen_dialog();
		}

		return false;
	}

	char error_str[256];
	char std_error_str[64];

	do_full_packet = true;

	In_process = true;

	if (Is_standalone) {
		do { rc = fs2netd_login_do(); } while (!rc);
	} else {
		rc = popup_till_condition(fs2netd_login_do, XSTR("&Cancel", 779), XSTR("Logging into FS2NetD", 1579));
	}

	In_process = false;
	Local_timeout = -1;

	memset( error_str, 0, sizeof(error_str) );
	memset( std_error_str, 0, sizeof(std_error_str) );

	switch (rc) {
		// the action was cancelled
		case 0:
			ml_string("FS2NetD MSG: Login process canceled by user.");
			retval = false;
			break;

		// didn't get a session id
		case 1: {
			const char *user = Multi_tracker_login;
			const char *passwd = Multi_tracker_passwd;

			if (Is_standalone) {
				if ( strlen(Multi_options_g.std_pxo_login) ) {
					user = Multi_options_g.std_pxo_login;
				}

				if ( strlen(Multi_options_g.std_pxo_password) ) {
					passwd = Multi_options_g.std_pxo_password;
				}
			}

			ml_printf("FS2NetD ERROR: Login %s/%s is invalid!", user, passwd);

			if (strlen(user) == 0) {
				strcpy_s(error_str, "Login failed! No username supplied. Go to options -> multi options and add one");
				strcpy_s(std_error_str, "Login failed! No username!");
			}
			else if (strlen(passwd) == 0) {
				strcpy_s(error_str, "Login failed! No password supplied. Go to options -> multi options and add one");
				strcpy_s(std_error_str, "Login failed! No password!");
			}
			else {
				strcpy_s(error_str, "Login failed!");
				strcpy_s(std_error_str, "Login failed!");
			}
			retval = false;
			break;
		}

		// unknown failure fetching pilot data
		case 2:
			ml_string("FS2NetD ERROR: UNKNOWN ERROR when fetching pilot data");
			strcpy_s(error_str, "An Unknown Error (probably a timeout) occured when trying to retrieve your pilot data.");
			strcpy_s(std_error_str, "Unknown Error (timeout?)");
			retval = false;
			break;

		// success!!
		case 3:
			ml_string("FS2NetD MSG: Got Pilot data");
			retval = true;
			break;

		// success!!  pilot was created
		case 4:
			ml_string("FS2NetD MSG: Created New Pilot");
			strcpy_s(error_str, "New Pilot has been created.");
			strcpy_s(std_error_str, "New Pilot has been created.");
			retval = true;
			break;

		// invalid pilot name
		case 5:
			ml_string("FS2NetD ERROR: Invalid Pilot!");
			strcpy_s(error_str, "Invalid pilot name - A serious error has occured, Contact the FS2NetD Administrator!");
			strcpy_s(std_error_str, "Invalid pilot name!");
			retval = false;
			break;

		// the session id was invalid
		case 6:
			ml_string("FS2NetD ERROR: Invalid SID!");
			strcpy_s(error_str, "Invalid SID - A serious error has occured, Contact the FS2NetD Administrator!");
			strcpy_s(std_error_str, "Invalid SID");
			retval = false;
			break;

		default:
			ml_string("FS2NetD ERROR: Unknown return case for GetPlayerData()");
			strcpy_s(error_str, "Unknown return case from GetPlayerData(). Contact the FS2NetD Administrator!");
			retval = false;
			break;
	}

	if ( !Is_standalone && strlen(error_str) ) {
		popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, error_str);
	} else if ( Is_standalone && std_gen_is_active() && strlen(std_error_str) ) {
		std_gen_set_text(std_error_str, 1);
		Sleep(2000);
	}

	if (retval) {
		Logged_in = true;
		sprintf(Multi_tracker_id_string, "%d", Multi_tracker_id);
	} else {
		// clear and reset connection, for the next time we try...
		fs2netd_disconnect();
	}

	if (Is_standalone) {
		std_destroy_gen_dialog();
	}

	return retval;
}
int fs2netd_login_do()
{
	if (Multi_tracker_id < 0) {
		if ( Is_standalone && std_gen_is_active() ) {
			std_gen_set_text("Verifying username and password", 1);
		} else {
			popup_change_text( XSTR("Verifying username and password", 1576) );
		}

		memset(Multi_tracker_id_string, 0, sizeof(Multi_tracker_id_string));

		if (Local_timeout == -1) {
			Local_timeout = timer_get_seconds() + 15;
		}

		// if timeout passes then bail on SID failure
		if ( timer_get_seconds() > Local_timeout ) {
			ml_string("FS2NetD MSG: Login failure due to timeout!");
			Local_timeout = -1;
			return 2;
		}

		const char *user = Multi_tracker_login;
		const char *passwd = Multi_tracker_passwd;

		if (Is_standalone) {
			if ( strlen(Multi_options_g.std_pxo_login) ) {
				user = Multi_options_g.std_pxo_login;
			}

			if ( strlen(Multi_options_g.std_pxo_password) ) {
				passwd = Multi_options_g.std_pxo_password;
			}
		}

		Multi_tracker_id = FS2NetD_Login(user, passwd, do_full_packet);

		// if we have already been through once then only deal with the recieve packet next time
		do_full_packet = false;

		// invalid login
		if (Multi_tracker_id == -2) {
			Multi_tracker_id = -1;
			Local_timeout = -1;
			return 1;
		}

		if (Multi_tracker_id >= 0) {
			ml_printf("FS2NetD MSG: Login '%s' is valid, session ID is %d!", user, Multi_tracker_id);
			do_full_packet = true;
			Local_timeout = -1;
		}
	} else {
		if ( Is_standalone && std_gen_is_active() ) {
			std_gen_set_text("Getting pilot stats", 1);
		} else {
			popup_change_text( XSTR("Getting pilot stats", 1577) );
		}

		if (Local_timeout == -1) {
			Local_timeout = timer_get_seconds() + 30;
		}

		// if timeout passes then bail on stats failure
		if ( timer_get_seconds() > Local_timeout ) {
		
			Local_timeout = -1;
			return 2;
		}

		if (do_full_packet) {
			ml_printf("FS2NetD MSG: Requesting login pilot stats for '%s' ...", Players[Player_num].callsign);
		}

		int rescode = FS2NetD_GetPlayerData(Players[Player_num].callsign, &Players[Player_num], true, do_full_packet);

		do_full_packet = false;

		if ( rescode != -1 ) {
			Local_timeout = -1;
			return (rescode + 3);
		}
	}

	return 0;
}
int fs2netd_update_valid_tables()
{
	int rc;
	int hacked = 0;

	if ( !Logged_in ) {
		return -1;
	}

	// if there are no tables to check with then bail
	if ( Table_valid_status.empty() ) {
		return -1;
	}

	// if we're a standalone, show a dialog saying "validating tables"
	if (Game_mode & GM_STANDALONE_SERVER) {
		std_create_gen_dialog("Validating tables");
		std_gen_set_text("Querying FS2NetD:", 1);
	}

	do_full_packet = true;

	In_process = true;

	if (Is_standalone) {
		do { rc = fs2netd_update_valid_tables_do(); } while (!rc);
	} else {
		rc = popup_till_condition(fs2netd_update_valid_tables_do, XSTR("&Cancel", 779), XSTR("Starting table validation", 1592));
	}

	In_process = false;
	Local_timeout = -1;

	switch (rc) {
		// canceled by popup
		case 0:
			return -1;

		// timed out
		case 1: {
			if ( !Is_standalone ) {
				popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Table validation timed out!", 1593));
			}

			return -1;
		}

		// no tables
		case 2: {
			if ( !Is_standalone ) {
				popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No tables are available from the server for validation!", 1594));
			}

			return -1;
		}
	}

	// output the status of table validity to multi.log
	for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) {
		if (tvs->valid) {
			ml_printf("FS2NetD Table Check: '%s' -- Valid!", tvs->name);
		} else {
			ml_printf("FS2NetD Table Check: '%s' -- INVALID (0x%x)!", tvs->name, tvs->crc32);
			hacked = 1;
		}
	}

	// if we're a standalone, kill the validate dialog
	if (Game_mode & GM_STANDALONE_SERVER) {
		std_destroy_gen_dialog();
	}

	return hacked;
}
int fs2netd_get_valid_missions_do()
{
	if (Local_timeout == -1) {
		Local_timeout = timer_get_seconds() + 30;
	}

	// get the available CRCs from the server if we need to
	if ( FS2NetD_file_list.empty() ) {
		int rc = FS2NetD_GetMissionsList(FS2NetD_file_list, do_full_packet);

		do_full_packet = false;

		// communications error
		if (rc < 0) {
			Local_timeout = -1;
			return 4;
		}

		// no missions
		if ( rc && FS2NetD_file_list.empty() ) {
			Local_timeout = -1;
			return 2;
		}

		// if timeout passes then bail on crc failure
		if ( timer_get_seconds() > Local_timeout ) {
			Local_timeout = -1;
			return 1;
		}
	}
	// we should have the CRCs, or there were no missions, so process them
	else {
		static char **file_names = NULL;
		static int idx = 0, count = 0;

		bool found = false;
		int file_index = 0;
		char valid_status = MVALID_STATUS_UNKNOWN;
		char full_name[MAX_FILENAME_LEN], wild_card[10];
		char val_text[MAX_FILENAME_LEN+15];
		uint checksum = 0;

		if (file_names == NULL) {
			// allocate filename space	
			file_names = (char**) vm_malloc_q( sizeof(char*) * 1024 ); // 1024 files should be safe!

			if (file_names == NULL) {
				Local_timeout = -1;
				return 3;
			}

			memset( wild_card, 0, sizeof(wild_card) );
			strcpy_s( wild_card, NOX("*") );
			strcat_s( wild_card, FS_MISSION_FILE_EXT );

			idx = count = cf_get_file_list(1024, file_names, CF_TYPE_MISSIONS, wild_card);
		}

		// drop idx first thing
		idx--;

		// we should be done validating, or just not have nothing to validate
		if (idx < 0) {
			for (idx = 0; idx < count; idx++) {
				if (file_names[idx] != NULL) {
					vm_free(file_names[idx]);
					file_names[idx] = NULL;
				}
			}

			vm_free(file_names);
			file_names = NULL;

			idx = count = 0;

			Local_timeout = -1;
			return 4;
		}


		// verify all filenames that we know about with their CRCs
		// NOTE: that this is done for one file per frame, since this is inside of a popup
		memset( full_name, 0, MAX_FILENAME_LEN );
		strncpy( full_name, cf_add_ext(file_names[idx], FS_MISSION_FILE_EXT), sizeof(full_name) - 1 );

		memset( val_text, 0, sizeof(val_text) );
		snprintf( val_text, sizeof(val_text) - 1, "Validating:  %s", full_name );

		if (Is_standalone) {
			if ( std_gen_is_active() ) {
				std_gen_set_text(val_text, 1);
			}
		} else {
			popup_change_text(val_text);
		}

		cf_chksum_long(full_name, &checksum);

		// try and find the file
		file_index = multi_create_lookup_mission(full_name);

		found = false;

		if (file_index >= 0) {
			for (SCP_vector<file_record>::iterator fr = FS2NetD_file_list.begin(); fr != FS2NetD_file_list.end() && !found; ++fr) {
				if ( !stricmp(full_name, fr->name) ) {
					if (fr->crc32 == checksum) {
						found = true;
						valid_status = MVALID_STATUS_VALID;
					} else {
						valid_status = MVALID_STATUS_INVALID;
					}

					Multi_create_mission_list[file_index].valid_status = valid_status;
				}
			}

			if (found) {
				ml_printf("FS2NetD Mission Validation: %s  =>  Valid!", full_name);
			} else {
				ml_printf("FS2NetD Mission Validation: %s  =>  INVALID! -- 0x%08x", full_name, checksum);
			}
		}
	}

	return 0;
}
int fs2netd_login_do()
{
	if (PXO_SID == -1) {
		if ( Is_standalone && std_gen_is_active() ) {
			std_gen_set_text("Verifying username and password", 1);
		} else {
			popup_change_text( XSTR("Verifying username and password", -1) );
		}

		if (timeout == -1) {
			timeout = timer_get_fixed_seconds() + (15 * F1_0);
		}

		// if timeout passes then bail on SID failure
		if ( timer_get_fixed_seconds() > timeout ) {
			timeout = -1;
			return 2;
		}

		PXO_SID = FS2NetD_Login(Multi_tracker_login, Multi_tracker_passwd, do_full_packet);

		// if we have already been through once then only deal with the recieve packet next time
		do_full_packet = 0;

		// invalid login
		if (PXO_SID == -2) {
			timeout = -1;
			return 1;
		}

		if (PXO_SID >= 0) {
			ml_printf("FS2NetD MSG: Login %s is valid, session ID is %i!", Multi_tracker_login, PXO_SID);
			do_full_packet = 1;
			timeout = -1;
		}
	} else {
		if ( Is_standalone && std_gen_is_active() ) {
			std_gen_set_text("Getting pilot stats", 1);
		} else {
			popup_change_text( XSTR("Getting pilot stats", -1) );
		}

		if (timeout == -1) {
			timeout = timer_get_fixed_seconds() + (30 * F1_0);
		}

		// if timeout passes then bail on stats failure
		if ( timer_get_fixed_seconds() > timeout ) {
			timeout = -1;
			return 2;
		}

		int rescode = FS2NetD_GetPlayerData(PXO_SID, Players[Player_num].callsign, &Players[Player_num], true, do_full_packet);

		do_full_packet = 0;

		if ( rescode != -1 ) {
			timeout = -1;
			return (rescode + 3);
		}
	}

	return 0;
}
int fs2netd_update_valid_tables()
{
	int rc;
	int hacked = 0;

	// if there are no tables to check with then bail
	if ( Table_valid_status.empty() ) {
		return -1;
	}

	// if we're not on FS2NetD then don't bother with this function
	if ( !Om_tracker_flag && (Game_mode & GM_MULTIPLAYER) ) {
		return -1;
	}

	// maybe try to init first
	fs2netd_connect();

	// if we didn't connect to FS2NetD then bail out now
	if ( !Is_connected ) {
		return -1;
	}

	// if we're a standalone, show a dialog saying "validating tables"
	if (Game_mode & GM_STANDALONE_SERVER) {
		std_create_gen_dialog("Validating tables");
		std_gen_set_text("Querying FS2NetD:", 1);
	}

	do_full_packet = 1;

	In_process = true;

	if (Is_standalone) {
		do { rc = fs2netd_update_valid_tables_do(); } while (!rc);
	} else {
		rc = popup_till_condition(fs2netd_update_valid_tables_do, XSTR("&Cancel", 779), XSTR("Starting table validation", -1));
	}

	In_process = false;

	switch (rc) {
		// canceled by popup
		case 0:
			return -1;

		// timed out
		case 1: {
			if ( !Is_standalone ) {
				popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Table validation timed out!", -1));
			}

			return -1;
		}

		// no tables
		case 2: {
			if ( !Is_standalone ) {
				popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No tables are available from the server for validation!", -1));
			}

			return -1;
		}
	}

	// output the status of table validity to multi.log
	for (uint i = 0; i < Table_valid_status.size(); i++) {
		if (Table_valid_status[i].valid) {
			ml_printf("FS2NetD Table Check: '%s' -- Valid!", Table_valid_status[i].name);
		} else {
			ml_printf("FS2NetD Table Check: '%s' -- INVALID (0x%x)!", Table_valid_status[i].name, Table_valid_status[i].crc32);
			hacked = 1;
		}
	}

	// if we're a standalone, kill the validate dialog
	if (Game_mode & GM_STANDALONE_SERVER) {
		std_destroy_gen_dialog();
	}

	return hacked;
}