openmohaa/code/gamespy/gstats/gp_stats/gp_statsDlg.cpp
2023-02-04 21:00:01 +01:00

733 lines
16 KiB
C++

// gp_statsDlg.cpp : implementation file
//
#include "stdafx.h"
#include "gp_stats.h"
#include "gp_statsDlg.h"
#include "../gpersist.h"
#include "../../ghttp/ghttp.h"
#include "../../common/gsAvailable.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// These are controls that are enabled when authenticated,
// and disabled when not authenticated.
//////////////////////////////////////////////////////////
CWnd * ToggleControls[64];
/////////////////////////////////////////////////////////////////////////////
// CGp_statsDlg dialog
CGp_statsDlg::CGp_statsDlg(CWnd* pParent /*=NULL*/)
: CDialog(CGp_statsDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CGp_statsDlg)
m_email = _T("dan@gamespy.com");
m_nick = _T("mrpants");
m_password = _T("mrpants");
m_profileID = 0;
m_type = 0;
m_value = _T("");
m_newKey = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CGp_statsDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CGp_statsDlg)
DDX_Control(pDX, IDC_KEYS, m_keys);
DDX_Text(pDX, IDC_EMAIL, m_email);
DDX_Text(pDX, IDC_NICK, m_nick);
DDX_Text(pDX, IDC_PASSWORD, m_password);
DDX_Text(pDX, IDC_PROFILE_ID, m_profileID);
DDX_Radio(pDX, IDC_PRIVATE_RW, m_type);
DDX_Text(pDX, IDC_VALUE, m_value);
DDX_Text(pDX, IDC_NEW_KEY, m_newKey);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CGp_statsDlg, CDialog)
//{{AFX_MSG_MAP(CGp_statsDlg)
ON_BN_CLICKED(IDC_AUTHENTICATE, OnAuthenticate)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_GET, OnGet)
ON_BN_CLICKED(IDC_SET, OnSet)
ON_BN_CLICKED(IDC_ADD, OnAdd)
ON_LBN_SELCHANGE(IDC_KEYS, OnSelchangeKeys)
ON_EN_CHANGE(IDC_VALUE, OnChangeValue)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGp_statsDlg message handlers
BOOL CGp_statsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// Build the list of toggle controls.
/////////////////////////////////////
int num = 0;
#define ADD_TOGGLE(id) ToggleControls[num++] = this->GetDlgItem(id)
ADD_TOGGLE(IDC_PRIVATE_RW);
ADD_TOGGLE(IDC_PRIVATE_RO);
ADD_TOGGLE(IDC_PUBLIC_RW);
ADD_TOGGLE(IDC_PUBLIC_RO);
ADD_TOGGLE(IDC_GET);
ADD_TOGGLE(IDC_SET);
ADD_TOGGLE(IDC_VALUE);
ADD_TOGGLE(IDC_KEYS);
ADD_TOGGLE(IDC_ADD);
ADD_TOGGLE(IDC_NEW_KEY);
ToggleControls[num++] = NULL;
// Init data.
/////////////
m_authenticated = FALSE;
m_gp = NULL;
// Put ourselves in the unauthenticated stats.
//////////////////////////////////////////////
UnAuthenticate();
// Init the connection to the stats manager.
////////////////////////////////////////////
CheckStatsConnection();
// Init GP.
///////////
if(gpInitialize(&m_gp, 0, 0, GP_PARTNERID_GAMESPY) != GP_NO_ERROR)
MessageBox("FAILED TO INITIALIZE GP!!!");
return TRUE; // return TRUE unless you set the focus to a control
}
void CGp_statsDlg::OnDestroy()
{
CDialog::OnDestroy();
ClearKeys();
// Close the stats connection.
//////////////////////////////
CloseStatsConnection();
// Shutdown GP.
///////////////
gpDestroy(&m_gp);
// Shutdown GHTTP.
//////////////////
ghttpCleanup();
}
void CGp_statsDlg::Authenticated()
{
m_authenticated = TRUE;
// Enable controls.
///////////////////
int i;
for(i = 0 ; ToggleControls[i] ; i++)
ToggleControls[i]->EnableWindow();
}
void CGp_statsDlg::UnAuthenticate()
{
m_authenticated = FALSE;
m_profileID = 0;
// Disable controls.
////////////////////
int i;
for(i = 0 ; ToggleControls[i] ; i++)
ToggleControls[i]->EnableWindow(FALSE);
}
BOOL CGp_statsDlg::CheckStatsConnection()
{
// Are we connected?
////////////////////
if(IsStatsConnected())
return TRUE;
// Set the gamename and secret key.
///////////////////////////////////
#if 1
strcpy(gcd_gamename, "gmtest");
gcd_secret_key[0] = 'H';
gcd_secret_key[1] = 'A';
gcd_secret_key[2] = '6';
gcd_secret_key[3] = 'z';
gcd_secret_key[4] = 'k';
gcd_secret_key[5] = 'S';
gcd_secret_key[7] = '\0';
#else
strcpy(gcd_gamename, "excessive");
gcd_secret_key[0] = 'G';
gcd_secret_key[1] = 'n';
gcd_secret_key[2] = '3';
gcd_secret_key[3] = 'a';
gcd_secret_key[4] = 'Y';
gcd_secret_key[5] = '9';
gcd_secret_key[7] = '\0';
#endif
// check that the game's backend is available
GSIACResult ac_result;
GSIStartAvailableCheck(gcd_gamename);
while((ac_result = GSIAvailableCheckThink()) == GSIACWaiting)
msleep(5);
if(ac_result != GSIACAvailable)
{
MessageBox("The backend is not available\n");
return TRUE;
}
// Try to connect.
//////////////////
int result = InitStatsConnection(0);
if(result == GE_NOERROR)
return TRUE;
// Error!
/////////
CString message;
if(result == GE_NOSOCKET)
message = "Unable to create a socket.";
else if(result == GE_NODNS)
message = "Unable to resolve a DNS name.";
else if(result == GE_NOCONNECT)
message = "Unable to connect to stats server, or connection lost.";
else if(result == GE_DATAERROR)
message = "Bad data from the stats server.";
else
message = "Error.";
MessageBox(message, "Error connecting to the stats server");
return FALSE;
}
void CGp_statsDlg::SendPassword()
{
// Form the URL for the request.
////////////////////////////////
CString URL = "http://gamespyarcade.com/software/reqemail.asp?email=";
URL += m_email;
// Set the wait cursor.
///////////////////////
HCURSOR hPrevCursor = GetCursor();
SetCursor(LoadCursor(NULL, IDC_WAIT));
// Do the request.
//////////////////
ghttpGetFile(URL, GHTTPTrue, NULL, NULL);
// Reset the previous cursor.
/////////////////////////////
SetCursor(hPrevCursor);
}
void CreateAccountCallback(GPConnection * connection, void * arg_, void * param)
{
GPNewUserResponseArg * arg = (GPNewUserResponseArg *)arg_;
int * pid = (int *)param;
// Store the result.
////////////////////
if(arg->result == GP_NO_ERROR)
*pid = arg->profile;
else
{
// If the nick was already in use, just pretend we created it.
//////////////////////////////////////////////////////////////
GPErrorCode errorCode;
gpGetErrorCode(connection, &errorCode);
if(errorCode == GP_NEWUSER_BAD_NICK)
*pid = arg->profile;
else
*pid = 0;
}
}
BOOL CGp_statsDlg::CreateAccount()
{
int pid;
int rcode;
// Create the account.
//////////////////////
GPResult result = gpNewUser(
&m_gp,
m_nick,
NULL,
m_email,
m_password,
NULL,
GP_BLOCKING,
CreateAccountCallback,
&pid);
if(result != GP_NO_ERROR)
{
MessageBox("There was an error creating the account.");
return FALSE;
}
// Check for success.
/////////////////////
if(pid)
{
m_profileID = pid;
return TRUE;
}
// Get the error code.
//////////////////////
GPErrorCode errorCode;
gpGetErrorCode(&m_gp, &errorCode);
// Handle the error code.
/////////////////////////
if(errorCode == GP_NEWUSER_BAD_PASSWORD)
{
rcode = MessageBox(
"You have entered an incorrect password for this e-mail address\n"
"Would you like the password sent to the e-mail address?",
NULL,
MB_YESNO);
// If no, we're done.
/////////////////////
if(rcode == IDNO)
return FALSE;
// Send the password.
/////////////////////
SendPassword();
return FALSE;
}
// An unknown error code.
/////////////////////////
MessageBox("There was an error creating the account.");
return FALSE;
}
void CheckAccountCallback(GPConnection * connection, void * arg_, void * param)
{
GPCheckResponseArg * arg = (GPCheckResponseArg *)arg_;
int * pid = (int *)param;
// Store the result.
////////////////////
if(arg->result == GP_NO_ERROR)
*pid = arg->profile;
else
*pid = 0;
}
BOOL CGp_statsDlg::CheckAccount()
{
int pid;
int rcode;
// Check for the account.
/////////////////////////
GPResult result = gpCheckUser(
&m_gp,
m_nick,
m_email,
m_password,
GP_BLOCKING,
CheckAccountCallback,
&pid);
if(result != GP_NO_ERROR)
{
MessageBox("There was an error authenticating the account.");
return FALSE;
}
// Check for success.
/////////////////////
if(pid)
{
m_profileID = pid;
return TRUE;
}
// Get the error code.
//////////////////////
GPErrorCode errorCode;
gpGetErrorCode(&m_gp, &errorCode);
// Handle the error code.
/////////////////////////
if(errorCode == GP_CHECK_BAD_EMAIL)
{
// Ask if they want to create the account.
//////////////////////////////////////////
rcode = MessageBox(
"This account does not exist.\n"
"Would you like to create it?",
NULL,
MB_YESNO);
// If no, we're done.
/////////////////////
if(rcode == IDNO)
return FALSE;
// Create the account.
//////////////////////
return CreateAccount();
}
else if(errorCode == GP_CHECK_BAD_NICK)
{
rcode = MessageBox(
"There are no profiles under this account with the nick you have entered\n"
"Would you like to create one?",
NULL,
MB_YESNO);
// If no, we're done.
/////////////////////
if(rcode == IDNO)
return FALSE;
// Create the account.
//////////////////////
return CreateAccount();
}
else if(errorCode == GP_CHECK_BAD_PASSWORD)
{
rcode = MessageBox(
"You have entered an incorrect password for this e-mail address\n"
"Would you like the password sent to the e-mail address?",
NULL,
MB_YESNO);
// If no, we're done.
/////////////////////
if(rcode == IDNO)
return FALSE;
// Send the password.
/////////////////////
SendPassword();
return FALSE;
}
// An unknown error code.
/////////////////////////
MessageBox("There was an error authenticating the account.");
return FALSE;
}
BOOL statsAuthFinished;
void StatsAuthenticationCallback(int localid, int profileid, int authenticated, char *errmsg, void *instance)
{
int * result = (int *)instance;
*result = authenticated;
if(authenticated != 1)
MessageBox(NULL, errmsg, "Error authenticating with the stats backend", MB_OK);
statsAuthFinished = TRUE;
}
BOOL CGp_statsDlg::StatsAuthentication()
{
char response[33];
int result;
// The auth call.
/////////////////
statsAuthFinished = FALSE;
PreAuthenticatePlayerPM(
0,
m_profileID,
GenerateAuth(GetChallenge(NULL), (char *)(LPCSTR)m_password, response),
StatsAuthenticationCallback,
&result);
// Wait for it to finish.
/////////////////////////
while(!statsAuthFinished)
if(!PersistThink())
CheckStatsConnection();
return (result == 1);
}
void CGp_statsDlg::OnAuthenticate()
{
// Update dialog members.
/////////////////////////
UpdateData();
// Sanity check args.
/////////////////////
if(!m_email.GetLength() || !m_nick.GetLength() || !m_password.GetLength())
{
MessageBox("E-mail, nick, and password must not be blank.");
return;
}
// If we're authenticated, unauthenticate.
//////////////////////////////////////////
if(m_authenticated)
UnAuthenticate();
// Check the account.
/////////////////////
if(!CheckAccount())
return;
// Do stats authentication.
///////////////////////////
if(!StatsAuthentication())
return;
// We're authenticated.
///////////////////////
Authenticated();
// Update dialog display.
/////////////////////////
UpdateData(FALSE);
}
persisttype_t TypeConversion(int type)
{
if(type == 0)
return pd_private_rw;
if(type == 1)
return pd_private_ro;
if(type == 2)
return pd_public_rw;
return pd_public_ro;
}
BOOL GetKeyValue(LPCSTR src, CString & key, CString & value)
{
const char * str;
const char * keyStart;
const char * valueStart;
int keyLen;
int valueLen;
// Check for no input.
//////////////////////
if(!src)
return FALSE;
// Check the starting \.
////////////////////////
if(src[0] != '\\')
return FALSE;
// Clear the key and value.
///////////////////////////
key.Empty();
value.Empty();
// Find the key and value, plus lengths.
////////////////////////////////////////
keyStart = (src + 1);
valueStart = strchr(keyStart, '\\');
if(!valueStart || (valueStart == keyStart))
return FALSE;
keyLen = (valueStart - keyStart);
valueStart++;
str = strchr(valueStart, '\\');
if(str)
valueLen = (str - valueStart);
else
valueLen = strlen(valueStart);
// Copy off the key.
////////////////////
char * keyStr = key.GetBuffer(keyLen);
memcpy(keyStr, keyStart, keyLen);
key.ReleaseBuffer(keyLen);
// Copy off the value.
////////////////////
char * valueStr = value.GetBuffer(valueLen);
memcpy(valueStr, valueStart, valueLen);
value.ReleaseBuffer(valueLen);
return TRUE;
}
void CGp_statsDlg::ClearKeys()
{
int count = m_keys.GetCount();
int i;
for(i = 0 ; i < count ; i++)
delete (CString *)m_keys.GetItemDataPtr(i);
m_keys.ResetContent();
}
void CGp_statsDlg::GotData(LPCSTR data)
{
CString key;
CString value;
int nIndex;
// Go through the keys/values.
//////////////////////////////
while(GetKeyValue(data, key, value))
{
// Adjust the data based on the key and value lengths.
//////////////////////////////////////////////////////
data += (key.GetLength() + value.GetLength() + 2);
// Add the new key/value.
/////////////////////////
nIndex = m_keys.AddString(key);
if(nIndex != -1)
m_keys.SetItemDataPtr(nIndex, new CString(value));
}
}
BOOL getDataFinished;
void GetDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, char *data, int len, void *instance)
{
getDataFinished = TRUE;
if(success)
{
CGp_statsDlg * dlg = (CGp_statsDlg *)instance;
dlg->GotData(data);
}
}
void CGp_statsDlg::OnGet()
{
// Update dialog members.
/////////////////////////
UpdateData();
// Clear the keys and value.
////////////////////////////
ClearKeys();
m_value.Empty();
// Make sure we're connected to the stats server.
/////////////////////////////////////////////////
if(!CheckStatsConnection())
return;
// Get the data.
////////////////
getDataFinished = FALSE;
GetPersistDataValues(0, m_profileID, TypeConversion(m_type), 0, "", GetDataCallback, this);
while(!getDataFinished)
if(!PersistThink())
CheckStatsConnection();
// Update dialog display.
/////////////////////////
UpdateData(FALSE);
}
BOOL setDataFinished;
void SetDataCallback(int localid, int profileid, persisttype_t type, int index, int success, time_t modified, void *instance)
{
setDataFinished = TRUE;
}
void CGp_statsDlg::OnSet()
{
// Update dialog members.
/////////////////////////
UpdateData();
// Make sure we're connected to the stats server.
/////////////////////////////////////////////////
if(!CheckStatsConnection())
return;
// Build the data string.
/////////////////////////
int count = m_keys.GetCount();
int i;
CString data;
CString key;
CString * value;
for(i = 0 ; i < count ; i++)
{
m_keys.GetText(i, key);
value = (CString *)m_keys.GetItemDataPtr(i);
data += '\\';
data += key;
data += '\\';
data += *value;
}
// Set some data.
/////////////////
setDataFinished = FALSE;
SetPersistDataValues(0, m_profileID, TypeConversion(m_type), 0, (char *)(LPCSTR)data, SetDataCallback, this);
while(!setDataFinished)
if(!PersistThink())
CheckStatsConnection();
}
void CGp_statsDlg::OnSelchangeKeys()
{
UpdateData();
// Get the new key/value.
/////////////////////////
int nIndex = m_keys.GetCurSel();
if(nIndex != -1)
m_value = *(CString *)m_keys.GetItemDataPtr(nIndex);
UpdateData(FALSE);
}
void CGp_statsDlg::OnAdd()
{
UpdateData();
if(m_newKey.IsEmpty())
return;
int nIndex = m_keys.AddString(m_newKey);
if(nIndex != -1)
m_keys.SetItemDataPtr(nIndex, new CString);
m_newKey.Empty();
UpdateData(FALSE);
}
void CGp_statsDlg::OnChangeValue()
{
UpdateData();
int nIndex = m_keys.GetCurSel();
if(nIndex != -1)
{
CString * string = (CString *)m_keys.GetItemDataPtr(nIndex);
*string = m_value;
}
}