openmohaa/code/gamespy/GP/gpiBuddy.c
2023-02-04 21:00:01 +01:00

1064 lines
35 KiB
C

/*
gpiBuddy.c
GameSpy Presence SDK
Dan "Mr. Pants" Schoenblum
Copyright 1999-2007 GameSpy Industries, Inc
devsupport@gamespy.com
***********************************************************************
Please see the GameSpy Presence SDK documentation for more information
**********************************************************************/
//INCLUDES
//////////
#include <stdlib.h>
#include <string.h>
#include "gpi.h"
//FUNCTIONS
///////////
static GPResult
gpiSendAuthBuddyRequest(
GPConnection * connection,
GPIProfile * profile
)
{
GPIConnection * iconnection = (GPIConnection*)*connection;
// Send the auth.
/////////////////
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\authadd\\");
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\fromprofileid\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profile->profileId);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sig\\");
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, profile->authSig);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\");
return GP_NO_ERROR;
}
GPResult
gpiProcessRecvBuddyMessage(
GPConnection * connection,
const char * input
)
{
char buffer[4096];
int type;
int profileid;
time_t date;
GPICallback callback;
GPIProfile * profile;
GPIBuddyStatus * buddyStatus;
char intValue[16];
char * str;
unsigned short port;
int productID;
GPIConnection * iconnection = (GPIConnection*)*connection;
char strTemp[max(GP_STATUS_STRING_LEN, GP_LOCATION_STRING_LEN)];
// Check the type of bm.
////////////////////////
if(!gpiValueForKey(input, "\\bm\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
type = atoi(buffer);
// Get the profile this is from.
////////////////////////////////
if(!gpiValueForKey(input, "\\f\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
profileid = atoi(buffer);
// Get the time.
////////////////
if(!gpiValueForKey(input, "\\date\\", buffer, sizeof(buffer)))
date = time(NULL);
else
date = atoi(buffer);
// What type of message is this?
////////////////////////////////
switch(type)
{
case GPI_BM_MESSAGE:
// Call the callback.
/////////////////////
callback = iconnection->callbacks[GPI_RECV_BUDDY_MESSAGE];
if(callback.callback != NULL)
{
GPRecvBuddyMessageArg * arg;
arg = (GPRecvBuddyMessageArg *)gsimalloc(sizeof(GPRecvBuddyMessageArg));
if(arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
#ifndef GSI_UNICODE
arg->message = (char *)gsimalloc(strlen(buffer) + 1);
if(arg->message == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
strcpy(arg->message, buffer);
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
#else
arg->message = (unsigned short*)gsimalloc(strlen(buffer)*2+2);
if(arg->message == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
UTF8ToUCS2String(buffer, arg->message);
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
#endif
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_MESSAGE));
}
break;
case GPI_BM_UTM:
// Call the callback.
/////////////////////
callback = iconnection->callbacks[GPI_RECV_BUDDY_UTM];
if(callback.callback != NULL)
{
GPRecvBuddyUTMArg * arg;
arg = (GPRecvBuddyUTMArg *)gsimalloc(sizeof(GPRecvBuddyUTMArg));
if(arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
#ifndef GSI_UNICODE
arg->message = (char *)gsimalloc(strlen(buffer) + 1);
if(arg->message == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
strcpy(arg->message, buffer);
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
#else
arg->message = (unsigned short*)gsimalloc(strlen(buffer)*2+2);
if(arg->message == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
UTF8ToUCS2String(buffer, arg->message);
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
#endif
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYUTM));
}
break;
case GPI_BM_REQUEST:
// Get the profile, adding if needed.
/////////////////////////////////////
profile = gpiProfileListAdd(connection, profileid);
if(!profile)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
// Get the reason.
//////////////////
if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Find where the sig starts.
/////////////////////////////
str = strstr(buffer, "|signed|");
if(str == NULL)
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Get the sig out of the message.
//////////////////////////////////
*str = '\0';
str += 8;
if(strlen(str) != 32)
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
freeclear(profile->authSig);
profile->authSig = goastrdup(str);
profile->requestCount++;
// Call the callback.
/////////////////////
callback = iconnection->callbacks[GPI_RECV_BUDDY_REQUEST];
if(callback.callback != NULL)
{
GPRecvBuddyRequestArg * arg;
arg = (GPRecvBuddyRequestArg *)gsimalloc(sizeof(GPRecvBuddyRequestArg));
if(arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
#ifndef GSI_UNICODE
strzcpy(arg->reason, buffer, GP_REASON_LEN);
#else
UTF8ToUCS2String(buffer, arg->reason);
#endif
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDDYREQUEST));
}
break;
case GPI_BM_AUTH:
// call the callback
callback = iconnection->callbacks[GPI_RECV_BUDDY_AUTH];
if(callback.callback != NULL)
{
GPRecvBuddyAuthArg * arg;
arg = (GPRecvBuddyAuthArg *)gsimalloc(sizeof(GPRecvBuddyAuthArg));
if (arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYAUTH));
}
break;
case GPI_BM_REVOKE:
// call the callback
callback = iconnection->callbacks[GPI_RECV_BUDDY_REVOKE];
if(callback.callback != NULL)
{
GPRecvBuddyRevokeArg * arg;
arg = (GPRecvBuddyRevokeArg *)gsimalloc(sizeof(GPRecvBuddyRevokeArg));
if (arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
arg->profile = (GPProfile)profileid;
arg->date = (unsigned int)date;
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYREVOKE));
}
break;
case GPI_BM_STATUS:
// Get the profile, adding if needed.
/////////////////////////////////////
profile = gpiProfileListAdd(connection, profileid);
if(!profile)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
// Make sure profile wasn't blocked prior to getting the status update
//////////////////////////////////////////////////////////////////////
if (!profile->blocked)
{
// This is a buddy.
///////////////////
if(!profile->buddyStatus)
{
profile->buddyStatus = (GPIBuddyStatus *)gsimalloc(sizeof(GPIBuddyStatus));
if(!profile->buddyStatus)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
memset(profile->buddyStatus, 0, sizeof(GPIBuddyStatus));
if (profile->buddyStatusInfo)
{
profile->buddyStatus->buddyIndex = profile->buddyStatusInfo->buddyIndex;
gpiRemoveBuddyStatusInfo(profile->buddyStatusInfo);
profile->buddyStatusInfo = NULL;
}
else
profile->buddyStatus->buddyIndex = iconnection->profileList.numBuddies++;
}
// Get the buddy status.
////////////////////////
buddyStatus = profile->buddyStatus;
// Get the msg.
///////////////
if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Get the status.
//////////////////
if(!gpiValueForKey(buffer, "|s|", intValue, sizeof(intValue)))
{
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
}
else
{
buddyStatus->status = (GPEnum)atoi(intValue);
}
// Get the status string.
/////////////////////////
freeclear(buddyStatus->statusString);
if(!gpiValueForKey(buffer, "|ss|", strTemp, GP_STATUS_STRING_LEN))
strTemp[0] = '\0';
buddyStatus->statusString = goastrdup(strTemp);
if(!buddyStatus->statusString)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
// Get the location string.
///////////////////////////
freeclear(buddyStatus->locationString);
if(!gpiValueForKey(buffer, "|ls|", strTemp, GP_LOCATION_STRING_LEN))
strTemp[0] = '\0';
buddyStatus->locationString = goastrdup(strTemp);
if(!buddyStatus->locationString)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
// Get the ip.
//////////////
if(!gpiValueForKey(buffer, "|ip|", intValue, sizeof(intValue)))
buddyStatus->ip = 0;
else
buddyStatus->ip = htonl((unsigned int)atoi(intValue));
// Get the port.
////////////////
if(!gpiValueForKey(buffer, "|p|", intValue, sizeof(intValue)))
buddyStatus->port = 0;
else
{
port = (unsigned short)atoi(intValue);
buddyStatus->port = htons(port);
}
// Get the quiet mode flags.
////////////////////////////
if(!gpiValueForKey(buffer, "|qm|", intValue, sizeof(intValue)))
buddyStatus->quietModeFlags = GP_SILENCE_NONE;
else
buddyStatus->quietModeFlags = (GPEnum)atoi(intValue);
// Call the callback.
/////////////////////
callback = iconnection->callbacks[GPI_RECV_BUDDY_STATUS];
if(callback.callback != NULL)
{
GPRecvBuddyStatusArg * arg;
arg = (GPRecvBuddyStatusArg *)gsimalloc(sizeof(GPRecvBuddyStatusArg));
if(arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
arg->profile = (GPProfile)profileid;
arg->index = buddyStatus->buddyIndex;
arg->date = (unsigned int)date;
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_STATUS));
}
}
break;
case GPI_BM_INVITE:
// Get the msg.
///////////////
if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Find the productid.
//////////////////////
str = strstr(buffer, "|p|");
if(str == NULL)
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Skip the |p|.
////////////////
str += 3;
if(str[0] == '\0')
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Get the productid.
/////////////////////
productID = atoi(str);
// Find the location string (optional - older versions won't have)
str = strstr(buffer, "|l|");
if(str != NULL)
strzcpy(strTemp, (str+3), sizeof(strTemp));
else
strTemp[0] = '\0'; // no location, set to empty string
// Call the callback.
/////////////////////
callback = iconnection->callbacks[GPI_RECV_GAME_INVITE];
if(callback.callback != NULL)
{
GPRecvGameInviteArg * arg;
arg = (GPRecvGameInviteArg *)gsimalloc(sizeof(GPRecvGameInviteArg));
if(arg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
arg->profile = (GPProfile)profileid;
arg->productID = productID;
#ifdef GSI_UNICODE
AsciiToUCS2String(strTemp, arg->location);
#else
strcpy(arg->location, strTemp);
#endif
CHECK_RESULT(gpiAddCallback(connection, callback, arg, NULL, 0));
}
break;
case GPI_BM_PING:
// Get the msg.
///////////////
if(!gpiValueForKey(input, "\\msg\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Send back a pong.
////////////////////
gpiSendBuddyMessage(connection, profileid, GPI_BM_PONG, "1", 0, NULL);
break;
#ifndef NOFILE
case GPI_BM_PONG:
// Lets the transfers handle this.
//////////////////////////////////
gpiTransfersHandlePong(connection, profileid, NULL);
break;
#endif
}
return GP_NO_ERROR;
}
GPResult gpiProcessRecvBuddyStatusInfo(GPConnection *connection, const char *input)
{
char buffer[1024];
int profileid;
time_t date;
GPICallback callback;
GPIProfile * profile;
GPIBuddyStatusInfo * buddyStatusInfo;
GPIConnection * iconnection = (GPIConnection*)*connection;
// This is what the message should look like. Its broken up for easy viewing.
//
// "\bsi\\state\\profile\\bip\\bport\\hostip\\hprivip\"
// "\qport\\hport\\sessflags\\rstatus\\gameType\"
// "\gameVnt\\gameMn\\product\\qmodeflags\"
////////////////////////////////
date = time(NULL);
// Get the buddy's profile
////////////////////////////////
if(!gpiValueForKey(input, "\\profile\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
profileid = atoi(buffer);
// Get the profile from the SDK's list, adding it if needed.
/////////////////////////////////////
profile = gpiProfileListAdd(connection, profileid);
if(!profile)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
// Make sure profile wasn't blocked prior to getting the status update
//////////////////////////////////////////////////////////////////////
if (!profile->blocked)
{
// This is a buddy.
///////////////////
if(!profile->buddyStatusInfo)
{
profile->buddyStatusInfo = (GPIBuddyStatusInfo *)gsimalloc(sizeof(GPIBuddyStatusInfo));
if(!profile->buddyStatusInfo)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
memset(profile->buddyStatusInfo, 0, sizeof(GPIBuddyStatusInfo));
if (profile->buddyStatus)
{
profile->buddyStatusInfo->buddyIndex = profile->buddyStatus->buddyIndex;
gpiRemoveBuddyStatus(profile->buddyStatus);
profile->buddyStatus = NULL;
}
else
profile->buddyStatusInfo->buddyIndex = iconnection->profileList.numBuddies++;
profile->buddyStatusInfo->extendedInfoKeys = ArrayNew(sizeof(GPIKey), GPI_INITIAL_NUM_KEYS, gpiStatusInfoKeyFree);
if (!profile->buddyStatusInfo->extendedInfoKeys)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
}
// extract the buddy status information and
// fill in appropriate information.
/////////////////////////////////////////////
buddyStatusInfo = profile->buddyStatusInfo;
if (!gpiValueForKey(input, "\\state\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->statusState = (GPEnum)atoi(buffer);
if (!gpiValueForKey(input, "\\bip\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->buddyIp = htonl((unsigned int)atoi(buffer));
if (!gpiValueForKey(input, "\\bport\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->buddyPort = (unsigned short)atoi(buffer);
if (!gpiValueForKey(input, "\\hostip\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->hostIp = htonl((unsigned int)atoi(buffer));
if (!gpiValueForKey(input, "\\hprivip\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->hostPrivateIp = htonl((unsigned int)atoi(buffer));
if (!gpiValueForKey(input, "\\qport\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->queryPort = (unsigned short)atoi(buffer);
if (!gpiValueForKey(input, "\\hport\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->hostPort = (unsigned short)atoi(buffer);
if (!gpiValueForKey(input, "\\sessflags\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->sessionFlags = (unsigned int)atoi(buffer);
freeclear(buddyStatusInfo->richStatus);
if (!gpiValueForKey(input, "\\rstatus\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->richStatus = goastrdup(buffer);
freeclear(buddyStatusInfo->gameType);
if (!gpiValueForKey(input, "\\gameType\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->gameType = goastrdup(buffer);
freeclear(buddyStatusInfo->gameVariant);
if (!gpiValueForKey(input, "\\gameVnt\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->gameVariant = goastrdup(buffer);
freeclear(buddyStatusInfo->gameMapName);
if (!gpiValueForKey(input, "\\gameMn\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->gameMapName = goastrdup(buffer);
if (!gpiValueForKey(input, "\\product\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->productId = (int)atoi(buffer);
if (!gpiValueForKey(input, "\\qmodeflags\\", buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
buddyStatusInfo->quietModeFlags = (GPEnum)atoi(buffer);
callback = iconnection->callbacks[GPI_RECV_BUDDY_STATUS];
if (callback.callback != NULL)
{
GPRecvBuddyStatusArg *anArg;
anArg = (GPRecvBuddyStatusArg *)gsimalloc(sizeof(GPRecvBuddyStatusArg));
if (anArg == NULL)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
anArg->date = (unsigned int)date;
anArg->index = buddyStatusInfo->buddyIndex;
anArg->profile = profileid;
CHECK_RESULT(gpiAddCallback(connection, callback, anArg, NULL, 0));
}
}
return GP_NO_ERROR;
}
GPResult
gpiProcessRecvBuddyList(
GPConnection * connection,
const char * input
)
{
int i=0, j=0;
int num = 0;
int index = 0;
char c;
char *str = NULL;
char buffer[512];
GPIProfile * profile;
GPProfile profileid;
GPIConnection * iconnection = (GPIConnection*)*connection;
// Check for an error.
//////////////////////
if(gpiCheckForError(connection, input, GPITrue))
return GP_SERVER_ERROR;
// Process Buddy List Retrieval msg - Format like:
/* ===============================================
\bdy\<num in list>\list\<block list - comma delimited>\final\
=============================================== */
if(!gpiValueForKeyWithIndex(input, "\\bdy\\", &index, buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
num = atoi(buffer);
// Check to make sure list is there
///////////////////////////////////
str = strstr(input, "\\list\\");
if (str == NULL)
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
// Then increment index to get ready for parsing
////////////////////////////////////////////////
str += 6;
index += 6;
for (i=0; i < num; i++)
{
if (i==0)
{
// Manually grab first profile in list - comma delimiter
////////////////////////////////////////////////////////
for(j=0 ; (j < sizeof(buffer)) && ((c = str[j]) != '\0') && (c != ',') ; j++)
{
buffer[j] = c;
}
buffer[j] = '\0';
index += j;
}
else
{
if(!gpiValueForKeyWithIndex(input, ",", &index, buffer, sizeof(buffer)))
CallbackFatalError(connection, GP_NETWORK_ERROR, GP_PARSE, "Unexpected data was received from the server.");
}
profileid = atoi(buffer);
// Get the profile, adding if needed.
/////////////////////////////////////
profile = gpiProfileListAdd(connection, profileid);
if(!profile)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
// Mark as offline buddy for now until we get the real status
/////////////////////////////////////////////////////////////
#ifdef GP_NEW_STATUS_INFO
// Use new status info as placeholder
profile->buddyStatusInfo = (GPIBuddyStatusInfo *)gsimalloc(sizeof(GPIBuddyStatusInfo));
if(!profile->buddyStatusInfo)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
memset(profile->buddyStatusInfo, 0, sizeof(GPIBuddyStatusInfo));
profile->buddyStatusInfo->extendedInfoKeys = ArrayNew(sizeof(GPIKey), GPI_INITIAL_NUM_KEYS, gpiStatusInfoKeyFree);
if (!profile->buddyStatusInfo->extendedInfoKeys)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
profile->buddyStatusInfo->buddyIndex = iconnection->profileList.numBuddies++;
profile->buddyStatusInfo->statusState = GP_OFFLINE;
#else
// Use buddy status as placeholder
profile->buddyStatus = (GPIBuddyStatus *)gsimalloc(sizeof(GPIBuddyStatus));
if(!profile->buddyStatus)
Error(connection, GP_MEMORY_ERROR, "Out of memory.");
memset(profile->buddyStatus, 0, sizeof(GPIBuddyStatus));
profile->buddyStatus->buddyIndex = iconnection->profileList.numBuddies++;
profile->buddyStatus->status = GP_OFFLINE;
#endif
}
return GP_NO_ERROR;
}
GPResult
gpiSendServerBuddyMessage(
GPConnection * connection,
int profileid,
int type,
const char * message
)
{
char buffer[3501];
GPIConnection * iconnection = (GPIConnection*)*connection;
// Copy the message into an internal buffer.
////////////////////////////////////////////
strzcpy(buffer, message, sizeof(buffer));
// Setup the message.
/////////////////////
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\bm\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, type);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\t\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, profileid);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\msg\\");
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, buffer);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\");
return GP_NO_ERROR;
}
GPResult
gpiSendBuddyMessage(
GPConnection * connection,
int profileid,
int type,
const char * message,
int sendOption,
GPIPeerOp *peerOp
)
{
GPIPeer * peer;
GPIProfile * profile;
//GPIConnection *iconnection = (GPIConnection *)*connection;
peer = gpiGetPeerByProfile(connection, profileid);
if(!peer)
{
// Check if we should send this through the server.
////////////////////////////////////////////////////
if(!gpiGetProfile(connection, profileid, &profile) ||
(!profile->buddyStatusInfo || !profile->buddyStatusInfo->buddyPort))
{
if (sendOption == GP_DONT_ROUTE)
return GP_NETWORK_ERROR;
return gpiSendServerBuddyMessage(connection, profileid, type, message);
}
// Create a new peer connection for this message.
/////////////////////////////////////////////////
peer = gpiAddPeer(connection, profileid, GPITrue);
if(!peer)
return GP_MEMORY_ERROR;
// Check if we need a sig.
//////////////////////////
if(!profile->peerSig)
{
// Get the sig.
///////////////
CHECK_RESULT(gpiPeerGetSig(connection, peer));
}
else
{
// Try to connect to the peer.
//////////////////////////////
CHECK_RESULT(gpiPeerStartConnect(connection, peer));
}
}
else if (peer->state == GPI_PEER_DISCONNECTED)
{
if (gpiGetProfile(connection, profileid, &profile))
{
// clear the buddy port to prevent future messages from
// being sent via UDP layer
if (profile->buddyStatusInfo)
profile->buddyStatusInfo->buddyPort = 0;
// send the message through the server
if (sendOption == GP_DONT_ROUTE)
return GP_NETWORK_ERROR;
if (type < 100)
return gpiSendServerBuddyMessage(connection, profileid, type, message);
}
}
if (peerOp)
{
gpiPeerAddOp(peer, peerOp);
}
// Copy the message.
////////////////////
CHECK_RESULT(gpiPeerAddMessage(connection, peer, type, message));
return GP_NO_ERROR;
}
GPResult gpiBuddyHandleKeyRequest(GPConnection *connection, GPIPeer *peer)
{
char *message;
// get all the keys and put them in the message part of bm
//////////////////////////////////////////////////////////
CHECK_RESULT(gpiSaveKeysToBuffer(connection, &message));
// Done in case we haven't set any keys
if (message == NULL)
message = "";
CHECK_RESULT(gpiSendBuddyMessage(connection, peer->profile, GPI_BM_KEYS_REPLY, message, GP_DONT_ROUTE, NULL));
if (strcmp(message, "")!= 0)
freeclear(message);
return GP_NO_ERROR;
}
GPResult gpiBuddyHandleKeyReply(GPConnection *connection, GPIPeer *peer, char *buffer)
{
GPIProfile *pProfile;
// Get the profile object to store the keys internally
//////////////////////////////////////////////////////
if(!gpiGetProfile(connection, peer->profile, &pProfile))
Error(connection, GP_PARAMETER_ERROR, "Invalid profile.");
// calculate the B64Decoded string len
if (strcmp(buffer, "") == 0)
{
GPIPeerOp *anIterator;
for (anIterator = peer->peerOpQueue.first; anIterator != NULL; anIterator = anIterator->next)
if (anIterator->type == GPI_BM_KEYS_REQUEST)
break;
if (!anIterator)
{
return GP_NO_ERROR;
}
else if (anIterator->type == GPI_BM_KEYS_REQUEST && anIterator->callback)
{
GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg));
GPICallback callback;
callback.callback = anIterator->callback;
callback.param = anIterator->userData;
arg->keys = NULL;
arg->numKeys = 0;
arg->values = NULL;
arg->profile = peer->profile;
gpiAddCallback(connection, callback, arg, NULL, 0);
gpiPeerRemoveOp(peer, anIterator);
}
}
else
{
int decodedLen = 0,
index = 0, numKeys, i;
char keyName[512];
char keyVal[512];
char decodeKey[512];
char decodeVal[512];
gsi_char **keys;
gsi_char **values;
GPIPeerOp *anIterator;
char *checkKey = NULL;
// start by getting the number of keys
gpiReadKeyAndValue(connection, buffer, &index, keyName, keyVal);
// do not continue further if the header is missing
if (strcmp(keyName, "keys") != 0)
CallbackError(connection, GP_NETWORK_ERROR, GP_PARSE, "Error reading keys reply message");
numKeys = atoi(keyVal);
if (numKeys == 0)
{
GPIPeerOp *anIterator;
for (anIterator = peer->peerOpQueue.first; anIterator != NULL; anIterator = anIterator->next)
if (anIterator->type == GPI_BM_KEYS_REQUEST)
break;
if (!anIterator)
{
return GP_NO_ERROR;
}
else if (anIterator->type == GPI_BM_KEYS_REQUEST && anIterator->callback)
{
GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg));
GPICallback callback;
callback.callback = anIterator->callback;
callback.param = anIterator->userData;
arg->keys = NULL;
arg->numKeys = 0;
arg->values = NULL;
arg->profile = peer->profile;
gpiAddCallback(connection, callback, arg, NULL, 0);
gpiPeerRemoveOp(peer, anIterator);
}
}
else
{
keys = (gsi_char **)gsimalloc(sizeof(gsi_char *) * numKeys);
values = (gsi_char **)gsimalloc(sizeof(gsi_char *) * numKeys);
for (i = 0; i < numKeys; i++)
{
gpiReadKeyAndValue(connection, buffer, &index, keyName, keyVal);
B64Decode(keyName, decodeKey, (int)strlen(keyName), &decodedLen, 2);
decodeKey[decodedLen] = '\0';
B64Decode(keyVal, decodeVal, (int)strlen(keyVal), &decodedLen, 2);
decodeVal[decodedLen] = '\0';
#ifdef GSI_UNICODE
keys[i] = UTF8ToUCS2StringAlloc(decodeKey);
values[i]= UTF8ToUCS2StringAlloc(decodeVal);
#else
keys[i] = goastrdup(decodeKey);
values[i] = goastrdup(decodeVal);
#endif
if (gpiStatusInfoCheckKey(connection, pProfile->buddyStatusInfo->extendedInfoKeys, decodeKey, &checkKey) == GP_NO_ERROR
&& checkKey == NULL)
{
gpiStatusInfoAddKey(connection, pProfile->buddyStatusInfo->extendedInfoKeys, decodeKey, decodeVal);
}
else
{
gpiStatusInfoSetKey(connection, pProfile->buddyStatusInfo->extendedInfoKeys, decodeKey, decodeVal);
}
}
for (anIterator = peer->peerOpQueue.first; anIterator != NULL; anIterator = anIterator->next)
if (anIterator->type == GPI_BM_KEYS_REQUEST)
break;
if (!anIterator)
{
return GP_NO_ERROR;
}
else if (anIterator->type == GPI_BM_KEYS_REQUEST && anIterator->callback)
{
GPICallback callback;
GPGetBuddyStatusInfoKeysArg *arg = (GPGetBuddyStatusInfoKeysArg *)gsimalloc(sizeof(GPGetBuddyStatusInfoKeysArg));
callback.callback = anIterator->callback;
callback.param = anIterator->userData;
// allocate a key array that points to each extended info key for that player
arg->numKeys = numKeys;
arg->keys = keys;
arg->values = values;
arg->profile = peer->profile;
gpiAddCallback(connection, callback, arg, NULL, GPI_ADD_BUDDYKEYS);
gpiPeerRemoveOp(peer, anIterator);
}
}
}
return GP_NO_ERROR;
}
GPResult gpiAuthBuddyRequest
(
GPConnection * connection,
GPProfile profile
)
{
GPIProfile * pProfile;
GPIConnection * iconnection = (GPIConnection*)*connection;
// Get the profile object.
//////////////////////////
if(!gpiGetProfile(connection, profile, &pProfile))
Error(connection, GP_PARAMETER_ERROR, "Invalid profile.");
// Check for a valid sig.
/////////////////////////
if(!pProfile->authSig)
Error(connection, GP_PARAMETER_ERROR, "Invalid profile.");
// Send the request.
////////////////////
CHECK_RESULT(gpiSendAuthBuddyRequest(connection, pProfile));
// freeclear the sig if no more requests.
////////////////////////////////////
pProfile->requestCount--;
if(!iconnection->infoCaching && (pProfile->requestCount <= 0))
{
freeclear(pProfile->authSig);
if(gpiCanFreeProfile(pProfile))
gpiRemoveProfile(connection, pProfile);
}
return GP_NO_ERROR;
}
GPIBool
gpiFixBuddyIndices(
GPConnection * connection,
GPIProfile * profile,
void * data
)
{
#ifndef _PS2
int baseIndex = (int)(unsigned long)data;
#else
int baseIndex = (int)data;
#endif
GSI_UNUSED(connection);
if(profile->buddyStatus && (profile->buddyStatus->buddyIndex > baseIndex))
profile->buddyStatus->buddyIndex--;
else if (profile->buddyStatusInfo && profile->buddyStatusInfo->buddyIndex > baseIndex)
profile->buddyStatusInfo->buddyIndex--;
return GPITrue;
}
GPResult
gpiDeleteBuddy(
GPConnection * connection,
GPProfile profile,
GPIBool sendServerRequest
)
{
GPIProfile * pProfile;
GPIConnection * iconnection = (GPIConnection*)*connection;
int index;
// Get the profile object.
//////////////////////////
if(!gpiGetProfile(connection, profile, &pProfile))
Error(connection, GP_PARAMETER_ERROR, "Invalid profile.");
// Check that this is a buddy.
//////////////////////////////
// Removed - 092404 BED - User could be a buddy even though we don't have the status
//if(!pProfile->buddyStatus)
// Error(connection, GP_PARAMETER_ERROR, "Profile not a buddy.");
// Send the request.
////////////////////
if (GPITrue == sendServerRequest)
{
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\delbuddy\\");
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\sesskey\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, iconnection->sessKey);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\delprofileid\\");
gpiAppendIntToBuffer(connection, &iconnection->outputBuffer, pProfile->profileId);
gpiAppendStringToBuffer(connection, &iconnection->outputBuffer, "\\final\\");
}
// Need to fix up the buddy indexes.
////////////////////////////////////
if (pProfile->buddyStatus)
{
index = pProfile->buddyStatus->buddyIndex;
assert(index >= 0);
freeclear(pProfile->buddyStatus->statusString);
freeclear(pProfile->buddyStatus->locationString);
freeclear(pProfile->buddyStatus);
if(gpiCanFreeProfile(pProfile))
gpiRemoveProfile(connection, pProfile);
iconnection->profileList.numBuddies--;
assert(iconnection->profileList.numBuddies >= 0);
#ifndef _PS2
gpiProfileMap(connection, gpiFixBuddyIndices, (void *)(unsigned long)index);
#else
gpiProfileMap(connection, gpiFixBuddyIndices, (void *)index);
#endif
}
if (pProfile->buddyStatusInfo)
{
index = pProfile->buddyStatusInfo->buddyIndex;
assert(index >= 0);
freeclear(pProfile->buddyStatusInfo->richStatus);
freeclear(pProfile->buddyStatusInfo->gameType);
freeclear(pProfile->buddyStatusInfo->gameVariant);
freeclear(pProfile->buddyStatusInfo->gameMapName);
freeclear(pProfile->buddyStatusInfo);
if (pProfile->buddyStatusInfo->extendedInfoKeys)
{
ArrayFree(pProfile->buddyStatusInfo->extendedInfoKeys);
pProfile->buddyStatusInfo->extendedInfoKeys = NULL;
}
if(gpiCanFreeProfile(pProfile))
gpiRemoveProfile(connection, pProfile);
iconnection->profileList.numBuddies--;
assert(iconnection->profileList.numBuddies >= 0);
#ifndef _PS2
gpiProfileMap(connection, gpiFixBuddyIndices, (void *)(unsigned long)index);
#else
gpiProfileMap(connection, gpiFixBuddyIndices, (void *)index);
#endif
}
return GP_NO_ERROR;
}