mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
1844 lines
40 KiB
C
1844 lines
40 KiB
C
/*
|
|
GameSpy Peer SDK
|
|
Dan "Mr. Pants" Schoenblum
|
|
dan@gamespy.com
|
|
|
|
Copyright 1999-2007 GameSpy Industries, Inc
|
|
|
|
devsupport@gamespy.com
|
|
*/
|
|
|
|
/*************
|
|
** INCLUDES **
|
|
*************/
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include "peerOperations.h"
|
|
#include "peerCallbacks.h"
|
|
#include "peerGlobalCallbacks.h"
|
|
#include "peerMangle.h"
|
|
#include "peerRooms.h"
|
|
#include "peerPlayers.h"
|
|
#include "peerKeys.h"
|
|
#include "peerSB.h"
|
|
#include "peerHost.h"
|
|
#include "peerAutoMatch.h"
|
|
#include "peerQR.h"
|
|
#include "../md5.h"
|
|
|
|
/************
|
|
** DEFINES **
|
|
************/
|
|
#define PI_CHAT_SERVER_ADDRESS "peerchat." GSI_DOMAIN_NAME
|
|
#define PI_CHAT_SERVER_PORT 6667
|
|
|
|
#define PEER_CONNECTION_OP piOperation * operation = (piOperation *)param;\
|
|
piConnection * connection = NULL;\
|
|
PEER peer = NULL;\
|
|
assert(operation && operation->peer);\
|
|
if(operation && operation->peer)\
|
|
peer = operation->peer;\
|
|
connection = (piConnection *)peer;\
|
|
GSI_UNUSED(connection);
|
|
#if 0
|
|
// for Visual Assist
|
|
PEER peer;
|
|
piOperation * operation;
|
|
#endif
|
|
|
|
/**********
|
|
** TYPES **
|
|
**********/
|
|
typedef struct piOperationContainer
|
|
{
|
|
piOperation * operation;
|
|
} piOperationContainer;
|
|
|
|
/**************
|
|
** FUNCTIONS **
|
|
**************/
|
|
#ifndef GSI_UNICODE
|
|
#define piGetGlobalKeysCallback piGetGlobalKeysCallbackA
|
|
#define piGetChannelKeysCallback piGetChannelKeysCallbackA
|
|
#define piGetPlayerInfoCallback piGetPlayerInfoCallbackA
|
|
#define piConnectNickErrorCallback piConnectNickErrorCallbackA
|
|
#define piConnectFillInUserCallback piConnectFillInUserCallbackA
|
|
#define piCreateStagingRoomEnumUsersCallback piCreateStagingRoomEnumUsersCallbackA
|
|
#define piCreateStagingRoomEnterChannelCallback piCreateStagingRoomEnterChannelCallbackA
|
|
#define piJoinRoomEnumUsersCallback piJoinRoomEnumUsersCallbackA
|
|
#define piJoinRoomEnterChannelCallback piJoinRoomEnterChannelCallbackA
|
|
#define piChangeNickCallback piChangeNickCallbackA
|
|
#define piAuthenticateCDKeyCallback piAuthenticateCDKeyCallbackA
|
|
#else
|
|
#define piGetGlobalKeysCallback piGetGlobalKeysCallbackW
|
|
#define piGetChannelKeysCallback piGetChannelKeysCallbackW
|
|
#define piGetPlayerInfoCallback piGetPlayerInfoCallbackW
|
|
#define piConnectNickErrorCallback piConnectNickErrorCallbackW
|
|
#define piConnectFillInUserCallback piConnectFillInUserCallbackW
|
|
#define piCreateStagingRoomEnumUsersCallback piCreateStagingRoomEnumUsersCallbackW
|
|
#define piCreateStagingRoomEnterChannelCallback piCreateStagingRoomEnterChannelCallbackW
|
|
#define piJoinRoomEnumUsersCallback piJoinRoomEnumUsersCallbackW
|
|
#define piJoinRoomEnterChannelCallback piJoinRoomEnterChannelCallbackW
|
|
#define piChangeNickCallback piChangeNickCallbackW
|
|
#define piAuthenticateCDKeyCallback piAuthenticateCDKeyCallbackW
|
|
#endif
|
|
|
|
static void piOperationsListFree(void *elem1)
|
|
{
|
|
piOperationContainer * container = (piOperationContainer *)elem1;
|
|
piOperation * operation;
|
|
|
|
assert(container);
|
|
assert(container->operation);
|
|
|
|
operation = container->operation;
|
|
|
|
// Free the name.
|
|
/////////////////
|
|
gsifree(operation->name);
|
|
|
|
// Free the password.
|
|
/////////////////////
|
|
gsifree(operation->password);
|
|
|
|
// Free the user data.
|
|
//////////////////////
|
|
gsifree(operation->data);
|
|
|
|
// Close the socket if needed.
|
|
//////////////////////////////
|
|
if(operation->socketClose)
|
|
{
|
|
closesocket(operation->socket);
|
|
SocketShutDown();
|
|
}
|
|
|
|
// Free the operation.
|
|
//////////////////////
|
|
gsifree(operation);
|
|
}
|
|
|
|
PEERBool piOperationsInit(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
assert(!connection->operationList);
|
|
|
|
// Init data.
|
|
/////////////
|
|
connection->operationsStarted = 0;
|
|
connection->operationsFinished = 0;
|
|
|
|
// Init the list.
|
|
/////////////////
|
|
connection->operationList = ArrayNew(sizeof(piOperationContainer), 0, piOperationsListFree);
|
|
if(!connection->operationList)
|
|
return PEERFalse;
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
void piOperationsReset(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Clear the list.
|
|
//////////////////
|
|
if(connection->operationList)
|
|
ArrayClear(connection->operationList);
|
|
|
|
// Clear the listingGroupsOperation
|
|
if (connection->listingGroupsOperation)
|
|
connection->listingGroupsOperation = NULL;
|
|
}
|
|
|
|
void piOperationsCleanup(PEER peer)
|
|
{
|
|
PEER_CONNECTION;
|
|
|
|
// Cleanup the list.
|
|
////////////////////
|
|
if(connection->operationList)
|
|
ArrayFree(connection->operationList);
|
|
connection->operationList = NULL;
|
|
}
|
|
|
|
void piRemoveOperation(PEER peer, piOperation * operation)
|
|
{
|
|
piOperationContainer * container;
|
|
piOperation * op;
|
|
int i;
|
|
int count;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
// Make sure there is a list.
|
|
/////////////////////////////
|
|
if(!connection->operationList)
|
|
return;
|
|
|
|
// Loop through the operations.
|
|
///////////////////////////////
|
|
count = ArrayLength(connection->operationList);
|
|
for(i = 0 ; i < count ; i++)
|
|
{
|
|
// Get the operation.
|
|
/////////////////////
|
|
container = (piOperationContainer *)ArrayNth(connection->operationList, i);
|
|
op = container->operation;
|
|
|
|
// Check the op.
|
|
////////////////
|
|
if(op == operation)
|
|
{
|
|
// Remove it.
|
|
/////////////
|
|
ArrayDeleteAt(connection->operationList, i);
|
|
|
|
// One more finished.
|
|
/////////////////////
|
|
connection->operationsFinished++;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
PEERBool piIsOperationFinished(PEER peer, int opID)
|
|
{
|
|
piOperationContainer * container;
|
|
piOperation * op;
|
|
int i;
|
|
int count;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
// Make sure there is a list.
|
|
/////////////////////////////
|
|
if(!connection->operationList)
|
|
return PEERTrue;
|
|
|
|
// Loop through the operations.
|
|
///////////////////////////////
|
|
count = ArrayLength(connection->operationList);
|
|
for(i = 0 ; i < count ; i++)
|
|
{
|
|
// Get the operation.
|
|
/////////////////////
|
|
container = (piOperationContainer *)ArrayNth(connection->operationList, i);
|
|
op = container->operation;
|
|
|
|
// Check the ID.
|
|
////////////////
|
|
if(op->ID == opID)
|
|
return PEERFalse;
|
|
}
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
void piCancelJoinOperation(PEER peer, RoomType roomType)
|
|
{
|
|
piOperationContainer * container;
|
|
piOperation * operation;
|
|
int i;
|
|
int count;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
// Make sure there is a list.
|
|
/////////////////////////////
|
|
if(!connection->operationList)
|
|
return;
|
|
|
|
// Loop through the operations.
|
|
///////////////////////////////
|
|
count = ArrayLength(connection->operationList);
|
|
for(i = 0 ; i < count ; i++)
|
|
{
|
|
// Get the operation.
|
|
/////////////////////
|
|
container = (piOperationContainer *)ArrayNth(connection->operationList, i);
|
|
operation = container->operation;
|
|
|
|
// Is it a join or create?
|
|
//////////////////////////
|
|
if((operation->type == PI_JOIN_ROOM_OPERATION) || (operation->type == PI_CREATE_ROOM_OPERATION))
|
|
{
|
|
// Is it the same room?
|
|
///////////////////////
|
|
if(operation->roomType == roomType)
|
|
{
|
|
// Cancel the operation.
|
|
////////////////////////
|
|
operation->cancel = PEERTrue;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int piGetNextID(PEER peer)
|
|
{
|
|
int ID;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
// Get the ID.
|
|
//////////////
|
|
ID = connection->nextID;
|
|
|
|
// Increment.
|
|
/////////////
|
|
connection->nextID++;
|
|
if(connection->nextID < 0)
|
|
connection->nextID = 0;
|
|
|
|
return ID;
|
|
}
|
|
|
|
static piOperation * piAddOperation
|
|
(
|
|
PEER peer,
|
|
piOperationType type,
|
|
void * data,
|
|
PEERCBType callback,
|
|
void * callbackParam,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
piOperationContainer container;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
//assert(type >= 0);
|
|
assert(type < PI_NUM_OPERATION_TYPES);
|
|
|
|
// Make sure there is a list.
|
|
/////////////////////////////
|
|
if(!connection->operationList)
|
|
return NULL;
|
|
|
|
// Alloc the operaiton.
|
|
///////////////////////
|
|
operation = (piOperation *)gsimalloc(sizeof(piOperation));
|
|
if(!operation)
|
|
return NULL;
|
|
|
|
// Fill in the operation.
|
|
/////////////////////////
|
|
memset(operation, 0, sizeof(piOperation));
|
|
operation->peer = peer;
|
|
operation->type = type;
|
|
operation->data = data;
|
|
operation->ID = opID;
|
|
operation->callback = callback;
|
|
operation->callbackParam = callbackParam;
|
|
operation->name = NULL;
|
|
operation->cancel = PEERFalse;
|
|
|
|
// Add the operation to the list.
|
|
/////////////////////////////////
|
|
container.operation = operation;
|
|
ArrayAppend(connection->operationList, &container);
|
|
|
|
// One more op.
|
|
///////////////
|
|
connection->operationsStarted++;
|
|
|
|
return operation;
|
|
}
|
|
|
|
/***************
|
|
** OPERATIONS **
|
|
***************/
|
|
|
|
/* Connect.
|
|
**********/
|
|
static void piConnectConnectCallback
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
int failureReason,
|
|
void *param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
// If successful, try and do the connect title stuff.
|
|
/////////////////////////////////////////////////////
|
|
if(success)
|
|
{
|
|
if(!piConnectTitle(peer))
|
|
{
|
|
piDisconnectTitle(peer);
|
|
success = CHATFalse;
|
|
}
|
|
}
|
|
|
|
// Connection attempt finished.
|
|
///////////////////////////////
|
|
connection->connecting = PEERFalse;
|
|
connection->connected = (PEERBool)success;
|
|
|
|
if(success)
|
|
{
|
|
const char * nick;
|
|
|
|
// Setup server pinging.
|
|
////////////////////////
|
|
connection->lastChatPing = current_time();
|
|
|
|
// Check the nick.
|
|
//////////////////
|
|
nick = chatGetNickA(chat);
|
|
if(strcasecmp(connection->nick, nick) != 0)
|
|
{
|
|
strcpy(connection->nick, nick);
|
|
|
|
#ifdef GSI_UNICODE
|
|
UTF8ToUCS2String(connection->nick, connection->nick_W);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Set the disconnect flag.
|
|
///////////////////////////
|
|
connection->disconnect = PEERTrue;
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
piAddConnectCallback(peer, (PEERBool)success, failureReason, (peerConnectCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
}
|
|
|
|
static void piConnectNickErrorCallbackA
|
|
(
|
|
CHAT chat,
|
|
int type,
|
|
const char * nick,
|
|
int numSuggestedNicks,
|
|
const char ** suggestedNicks,
|
|
void *param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Add the peer callback.
|
|
/////////////////////////
|
|
piAddNickErrorCallback(peer, type, nick, numSuggestedNicks, suggestedNicks, operation->callbackParam, operation->ID);
|
|
|
|
GSI_UNUSED(chat);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piConnectNickErrorCallbackW
|
|
(
|
|
CHAT chat,
|
|
int type,
|
|
const unsigned short * nick,
|
|
int numSuggestedNicks,
|
|
const unsigned short ** suggestedNicks,
|
|
void *param
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char** suggestedNicks_A = UCS2ToUTF8StringArrayAlloc(suggestedNicks, numSuggestedNicks);
|
|
int i;
|
|
piConnectNickErrorCallbackA(chat, type, nick_A, numSuggestedNicks, (const char**)suggestedNicks_A, param);
|
|
gsifree(nick_A);
|
|
if(suggestedNicks_A)
|
|
{
|
|
for (i=0; i<numSuggestedNicks; i++)
|
|
gsifree(suggestedNicks_A[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static void piConnectFillInUserCallbackA
|
|
(
|
|
CHAT chat,
|
|
unsigned int IP,
|
|
char user[128],
|
|
void * param
|
|
)
|
|
{
|
|
int pid;
|
|
|
|
PEER_CONNECTION_OP;
|
|
|
|
// 2004.Sep.17.JED - For reasons unknown, in the span of one month Arcade's automated
|
|
// crash handling system reported +15 null pointer crashes when publicIP was stored.
|
|
//////////////////////////////////////////////////////////////////////////////////////
|
|
if( !connection )
|
|
return;
|
|
|
|
// Store the public IP.
|
|
///////////////////////
|
|
connection->publicIP = IP;
|
|
|
|
// If chat has a pid, override ours.
|
|
////////////////////////////////////
|
|
pid = chatGetProfileID(connection->chat);
|
|
if(pid)
|
|
connection->profileID = pid;
|
|
|
|
// Mangle the IP and pid into the user.
|
|
///////////////////////////////////////
|
|
piMangleUser(user, connection->publicIP, connection->profileID);
|
|
|
|
GSI_UNUSED(chat);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piConnectFillInUserCallbackW
|
|
(
|
|
CHAT chat,
|
|
unsigned int IP,
|
|
unsigned short user[128], // OUT parameter!!
|
|
void * param
|
|
)
|
|
{
|
|
// This one is reversed! Call the callback, THEN convert
|
|
char user_A[256];
|
|
piConnectFillInUserCallbackA(chat, IP, user_A, param);
|
|
UTF8ToUCS2String(user_A, user);
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewConnectOperation
|
|
(
|
|
PEER peer,
|
|
piConnectType connectType,
|
|
const char * nick,
|
|
int namespaceID,
|
|
const char * email,
|
|
const char * profilenick,
|
|
const char * uniquenick,
|
|
const char * password,
|
|
const char * authtoken,
|
|
const char * partnerchallenge,
|
|
peerConnectCallback callback,
|
|
void * callbackParam,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
chatGlobalCallbacks globalCallbacks;
|
|
const char * uniqueID;
|
|
char encodedUniqueID[33];
|
|
peerNickErrorCallback nickErrorCallback;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(callback);
|
|
|
|
#ifdef _DEBUG
|
|
if(connectType == PI_CONNECT)
|
|
{
|
|
assert(nick && nick[0]);
|
|
}
|
|
else if(connectType == PI_CONNECT_UNIQUENICK_LOGIN)
|
|
{
|
|
assert(namespaceID > 0);
|
|
assert(uniquenick && uniquenick[0]);
|
|
assert(password && password[0]);
|
|
}
|
|
else if(connectType == PI_CONNECT_PROFILENICK_LOGIN)
|
|
{
|
|
assert(namespaceID >= 0);
|
|
assert(email && email[0]);
|
|
assert(profilenick && profilenick[0]);
|
|
assert(password && password[0]);
|
|
}
|
|
else if(connectType == PI_CONNECT_PREAUTH)
|
|
{
|
|
assert(authtoken && authtoken[0]);
|
|
assert(partnerchallenge && partnerchallenge[0]);
|
|
}
|
|
#endif
|
|
|
|
// Add an operation.
|
|
////////////////////
|
|
operation = piAddOperation(peer, PI_CONNECT_OPERATION, NULL, (PEERCBType)callback, callbackParam, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Setup the global callbacks.
|
|
//////////////////////////////
|
|
memset(&globalCallbacks, 0, sizeof(chatGlobalCallbacks));
|
|
globalCallbacks.disconnected = piChatDisconnected;
|
|
globalCallbacks.privateMessage = piChatPrivateMessage;
|
|
globalCallbacks.param = peer;
|
|
|
|
// Encode the unique ID.
|
|
////////////////////////
|
|
uniqueID = GOAGetUniqueID();
|
|
MD5Digest((unsigned char *)uniqueID, strlen(uniqueID), encodedUniqueID);
|
|
|
|
// Connect to chat.
|
|
///////////////////
|
|
nickErrorCallback = (connection->nickErrorCallback ? piConnectNickErrorCallback : NULL);
|
|
if(connectType == PI_CONNECT)
|
|
{
|
|
connection->chat = chatConnectSecureA(
|
|
PI_CHAT_SERVER_ADDRESS,
|
|
PI_CHAT_SERVER_PORT,
|
|
nick,
|
|
encodedUniqueID,
|
|
connection->sbName,
|
|
connection->sbSecretKey,
|
|
&globalCallbacks,
|
|
nickErrorCallback,
|
|
piConnectFillInUserCallback,
|
|
piConnectConnectCallback,
|
|
operation,
|
|
CHATFalse);
|
|
}
|
|
else if((connectType == PI_CONNECT_UNIQUENICK_LOGIN) || (connectType == PI_CONNECT_PROFILENICK_LOGIN))
|
|
{
|
|
connection->chat = chatConnectLoginA(
|
|
PI_CHAT_SERVER_ADDRESS,
|
|
PI_CHAT_SERVER_PORT,
|
|
namespaceID,
|
|
email,
|
|
profilenick,
|
|
uniquenick,
|
|
password,
|
|
encodedUniqueID,
|
|
connection->sbName,
|
|
connection->sbSecretKey,
|
|
&globalCallbacks,
|
|
nickErrorCallback,
|
|
piConnectFillInUserCallback,
|
|
piConnectConnectCallback,
|
|
operation,
|
|
CHATFalse);
|
|
}
|
|
else if(connectType == PI_CONNECT_PREAUTH)
|
|
{
|
|
connection->chat = chatConnectPreAuthA(
|
|
PI_CHAT_SERVER_ADDRESS,
|
|
PI_CHAT_SERVER_PORT,
|
|
authtoken,
|
|
partnerchallenge,
|
|
encodedUniqueID,
|
|
connection->sbName,
|
|
connection->sbSecretKey,
|
|
&globalCallbacks,
|
|
nickErrorCallback,
|
|
piConnectFillInUserCallback,
|
|
piConnectConnectCallback,
|
|
operation,
|
|
CHATFalse);
|
|
}
|
|
if(!connection->chat)
|
|
{
|
|
piRemoveOperation(peer, operation);
|
|
return PEERFalse;
|
|
}
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* Create Staging Room.
|
|
**********************/
|
|
static PEERJoinResult piEnterResultToJoinResult
|
|
(
|
|
CHATEnterResult result
|
|
)
|
|
{
|
|
switch(result)
|
|
{
|
|
case CHATEnterSuccess:
|
|
return PEERJoinSuccess;
|
|
case CHATChannelIsFull:
|
|
return PEERFullRoom;
|
|
case CHATInviteOnlyChannel:
|
|
return PEERInviteOnlyRoom;
|
|
case CHATBannedFromChannel:
|
|
return PEERBannedFromRoom;
|
|
case CHATBadChannelPassword:
|
|
return PEERBadPassword;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return PEERJoinFailed;
|
|
}
|
|
|
|
static void piCreateStagingRoomEnumUsersCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const char * channel,
|
|
int numUsers,
|
|
const char ** users,
|
|
int * modes,
|
|
void *param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Check if this was cancelled.
|
|
///////////////////////////////
|
|
if(operation->cancel)
|
|
{
|
|
piRemoveOperation(peer, operation);
|
|
return;
|
|
}
|
|
|
|
// Start hosting/reporting.
|
|
///////////////////////////
|
|
if(success)
|
|
{
|
|
if(!peerIsAutoMatching(peer))
|
|
{
|
|
if(!piStartHosting(peer, operation->socket, operation->port))
|
|
success = CHATFalse;
|
|
else
|
|
{
|
|
// If we created the socket, hand over responsibility for it to qr2.
|
|
////////////////////////////////////////////////////////////////////
|
|
if(operation->socketClose)
|
|
{
|
|
operation->socketClose = PEERFalse;
|
|
connection->queryReporting->read_socket = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
connection->hosting = PEERTrue;
|
|
}
|
|
}
|
|
|
|
// Do stuff based on success.
|
|
/////////////////////////////
|
|
if(success)
|
|
{
|
|
int i;
|
|
|
|
// Done entering.
|
|
/////////////////
|
|
piFinishedEnteringRoom(peer, StagingRoom, operation->name);
|
|
|
|
// Add everyone to the room.
|
|
////////////////////////////
|
|
for(i = 0 ; i < numUsers ; i++)
|
|
piPlayerJoinedRoom(peer, users[i], StagingRoom, modes[i]);
|
|
|
|
// Set the name.
|
|
////////////////
|
|
chatSetChannelTopicA(connection->chat, channel, operation->name);
|
|
|
|
// Set a limit on the room.
|
|
///////////////////////////
|
|
#ifndef PI_NO_STAGING_ROOM_LIMIT
|
|
if(connection->maxPlayers)
|
|
chatSetChannelLimitA(connection->chat, channel, connection->maxPlayers);
|
|
#endif
|
|
|
|
// If this is AutoMatch, and we created a socket, hand it over.
|
|
///////////////////////////////////////////////////////////////
|
|
if(operation->socketClose && peerIsAutoMatching(peer))
|
|
{
|
|
connection->autoMatchOperation->socket = operation->socket;
|
|
connection->autoMatchOperation->port = operation->port;
|
|
connection->autoMatchOperation->socketClose = PEERTrue;
|
|
operation->socketClose = PEERFalse;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Leave the room.
|
|
//////////////////
|
|
piLeaveRoom(peer, StagingRoom, NULL);
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
piAddJoinRoomCallback(peer, (PEERBool)success, success?PEERJoinSuccess:PEERJoinFailed, StagingRoom, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piCreateStagingRoomEnumUsersCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const unsigned short * channel,
|
|
int numUsers,
|
|
const unsigned short ** users,
|
|
int * modes,
|
|
void *param
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
char** users_A = UCS2ToUTF8StringArrayAlloc(users, numUsers);
|
|
int i;
|
|
piCreateStagingRoomEnumUsersCallbackA(chat, success, channel_A, numUsers, (const char**)users_A, modes, param);
|
|
gsifree(channel_A);
|
|
for (i=0; i<numUsers; i++)
|
|
gsifree(users_A[i]);
|
|
gsifree(users_A);
|
|
}
|
|
#endif
|
|
|
|
|
|
static void piCreateStagingRoomGetChannelModeCallback(CHAT chat, CHATBool success, const gsi_char * channel,
|
|
CHATChannelMode * mode, void * param)
|
|
{
|
|
piConnection *connection = (piConnection *)param;
|
|
if (success)
|
|
{
|
|
|
|
mode->Limit = connection->maxPlayers;
|
|
mode->OpsObeyChannelLimit = CHATTrue;
|
|
|
|
// Don't let ops bypass channel limit on the number of players in room
|
|
chatSetChannelMode(chat, channel, mode);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
static void piCreateStagingRoomEnterChannelCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
CHATEnterResult result,
|
|
const char * channel,
|
|
void *param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
assert(channel);
|
|
assert(channel[0]);
|
|
|
|
// Check if this was cancelled.
|
|
///////////////////////////////
|
|
if(operation->cancel)
|
|
{
|
|
piRemoveOperation(peer, operation);
|
|
return;
|
|
}
|
|
|
|
if(success)
|
|
{
|
|
// If passworded, set it.
|
|
/////////////////////////
|
|
if(operation->password)
|
|
chatSetChannelPasswordA(connection->chat, channel, CHATTrue, operation->password);
|
|
|
|
|
|
// get the channel modes so we can set the limits on our staging channel
|
|
chatGetChannelMode(connection->chat, peerGetRoomChannel(peer, StagingRoom), piCreateStagingRoomGetChannelModeCallback,
|
|
(void *)connection, CHATFalse);
|
|
|
|
|
|
// How many users?
|
|
//////////////////
|
|
chatEnumUsersA(chat, channel, piCreateStagingRoomEnumUsersCallback, operation, CHATFalse);
|
|
}
|
|
else
|
|
{
|
|
PEERJoinResult joinResult;
|
|
|
|
// Not entering.
|
|
////////////////
|
|
piLeaveRoom(peer, StagingRoom, NULL);
|
|
|
|
// Get the peer result.
|
|
///////////////////////
|
|
if(result == CHATEnterSuccess)
|
|
joinResult = PEERJoinFailed;
|
|
else
|
|
joinResult = piEnterResultToJoinResult(result);
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
piAddJoinRoomCallback(peer, PEERFalse, joinResult, StagingRoom, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
}
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piCreateStagingRoomEnterChannelCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
CHATEnterResult result,
|
|
const unsigned short * channel,
|
|
void *param
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
piCreateStagingRoomEnterChannelCallbackA(chat, success, result, channel_A, param);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
// internal QR2 function
|
|
qr2_error_t qr2_create_socket(/*[out]*/SOCKET *sock, const char *ip, /*[in/out]*/int * port);
|
|
|
|
PEERBool piNewCreateStagingRoomOperation
|
|
(
|
|
PEER peer,
|
|
const char * name,
|
|
const char * password,
|
|
int maxPlayers,
|
|
SOCKET socket,
|
|
unsigned short port,
|
|
peerJoinRoomCallback callback,
|
|
void * callbackParam,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
chatChannelCallbacks channelCallbacks;
|
|
char room[PI_ROOM_MAX_LEN];
|
|
PEERBool createdSocket = PEERFalse;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(name);
|
|
if(!name)
|
|
name = "";
|
|
|
|
assert(callback);
|
|
if(!callback)
|
|
return PEERFalse;
|
|
|
|
// Save off the maxplayers.
|
|
///////////////////////////
|
|
connection->maxPlayers = maxPlayers;
|
|
|
|
// If we don't have a socket, create one to use.
|
|
////////////////////////////////////////////////
|
|
if(socket == INVALID_SOCKET)
|
|
{
|
|
IN_ADDR addr;
|
|
qr2_error_t rcode;
|
|
int privatePort;
|
|
|
|
addr.s_addr = 0;//crt -- don't bind to privateIP (for clients that have both public and private) connection->privateIP;
|
|
if(port)
|
|
privatePort = port;
|
|
else
|
|
privatePort = PI_QUERYPORT;
|
|
|
|
rcode = qr2_create_socket(&socket, inet_ntoa(addr), &privatePort);
|
|
if(rcode != e_qrnoerror)
|
|
return PEERFalse;
|
|
|
|
port = (unsigned short)privatePort;
|
|
createdSocket = PEERTrue;
|
|
}
|
|
|
|
// Get the room name.
|
|
/////////////////////
|
|
piMangleStagingRoom(room, connection->title, connection->publicIP, connection->privateIP, port);
|
|
assert(room[0]);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_CREATE_ROOM_OPERATION, NULL, (PEERCBType)callback, callbackParam, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
operation->socketClose = createdSocket;
|
|
operation->name = goastrdup(name);
|
|
if(!operation->name)
|
|
{
|
|
piRemoveOperation(peer, operation);
|
|
return PEERFalse;
|
|
}
|
|
operation->socket = socket;
|
|
operation->port = port;
|
|
operation->roomType = StagingRoom;
|
|
if(password[0])
|
|
operation->password = goastrdup(password);
|
|
|
|
// Set the callbacks.
|
|
/////////////////////
|
|
piSetChannelCallbacks(peer, &channelCallbacks);
|
|
|
|
// Create the room.
|
|
///////////////////
|
|
piStartedEnteringRoom(peer, StagingRoom, room);
|
|
chatEnterChannelA(connection->chat, room, NULL, &channelCallbacks, piCreateStagingRoomEnterChannelCallback, operation, CHATFalse);
|
|
|
|
// Store passworded flag if needed.
|
|
///////////////////////////////////
|
|
if(password[0])
|
|
connection->passwordedRoom = PEERTrue;
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* Join Room.
|
|
************/
|
|
static void piJoinRoomEnumUsersCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const char * channel,
|
|
int numUsers,
|
|
const char ** users,
|
|
int * modes,
|
|
void * param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Check if this was cancelled.
|
|
///////////////////////////////
|
|
if(operation->cancel)
|
|
{
|
|
piRemoveOperation(peer, operation);
|
|
return;
|
|
}
|
|
|
|
// Check for success.
|
|
/////////////////////
|
|
if(success)
|
|
{
|
|
int i;
|
|
|
|
// Finished entering the room.
|
|
//////////////////////////////
|
|
piFinishedEnteringRoom(peer, operation->roomType, "");
|
|
|
|
// Add all these people to the room.
|
|
////////////////////////////////////
|
|
for(i = 0 ; i < numUsers ; i++)
|
|
piPlayerJoinedRoom(peer, users[i], operation->roomType, modes[i]);
|
|
}
|
|
else
|
|
{
|
|
// Leave the room.
|
|
//////////////////
|
|
piLeaveRoom(peer, operation->roomType, NULL);
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
piAddJoinRoomCallback(peer, (PEERBool)success, success?PEERJoinSuccess:PEERJoinFailed, operation->roomType, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
GSI_UNUSED(channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piJoinRoomEnumUsersCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const unsigned short * channel,
|
|
int numUsers,
|
|
const unsigned short ** users,
|
|
int * modes,
|
|
void * param
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
char** users_A = UCS2ToUTF8StringArrayAlloc(users, numUsers);
|
|
int i;
|
|
piJoinRoomEnumUsersCallbackA(chat, success, channel_A, numUsers, (const char**)users_A, modes, param);
|
|
gsifree(channel_A);
|
|
for (i=0; i<numUsers; i++)
|
|
gsifree(users_A[i]);
|
|
gsifree(users_A);
|
|
}
|
|
#endif
|
|
|
|
static void piJoinRoomEnterChannelCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
CHATEnterResult result,
|
|
const char * channel,
|
|
void *param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
assert(channel);
|
|
assert(channel[0]);
|
|
|
|
// Check if this was cancelled.
|
|
///////////////////////////////
|
|
if(operation->cancel)
|
|
{
|
|
piSBFreeHostServer(peer);
|
|
piRemoveOperation(peer, operation);
|
|
return;
|
|
}
|
|
|
|
if(success)
|
|
{
|
|
// How many users?
|
|
//////////////////
|
|
chatEnumUsersA(chat, channel, piJoinRoomEnumUsersCallback, operation, CHATFalse);
|
|
}
|
|
else
|
|
{
|
|
PEERJoinResult joinResult;
|
|
|
|
// Not entering.
|
|
////////////////
|
|
piLeaveRoom(peer, operation->roomType, NULL);
|
|
|
|
// Get the peer result.
|
|
///////////////////////
|
|
if(result == CHATEnterSuccess)
|
|
joinResult = PEERJoinFailed;
|
|
else
|
|
joinResult = piEnterResultToJoinResult(result);
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
piAddJoinRoomCallback(peer, PEERFalse, joinResult, operation->roomType, (peerJoinRoomCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
}
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piJoinRoomEnterChannelCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
CHATEnterResult result,
|
|
const unsigned short * channel,
|
|
void *param
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
piJoinRoomEnterChannelCallbackA(chat, success, result, channel_A, param);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewJoinRoomOperation
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * channel,
|
|
const char * password,
|
|
peerJoinRoomCallback callback,
|
|
void * callbackParam,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
chatChannelCallbacks channelCallbacks;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(callback);
|
|
|
|
// Check the name.
|
|
//////////////////
|
|
assert(channel);
|
|
assert(channel[0]);
|
|
if(!channel || !channel[0])
|
|
return PEERFalse;
|
|
|
|
// Check password.
|
|
//////////////////
|
|
if(!password)
|
|
password = "";
|
|
|
|
// Check that the name isn't too long.
|
|
//////////////////////////////////////
|
|
assert(strlen(channel) < PI_ROOM_MAX_LEN);
|
|
if(strlen(channel) >= PI_ROOM_MAX_LEN)
|
|
return PEERFalse;
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_JOIN_ROOM_OPERATION, NULL, (PEERCBType)callback, callbackParam, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
operation->roomType = roomType;
|
|
|
|
// Set the callbacks.
|
|
/////////////////////
|
|
piSetChannelCallbacks(peer, &channelCallbacks);
|
|
|
|
// Join the room.
|
|
/////////////////
|
|
piStartedEnteringRoom(peer, roomType, channel);
|
|
chatEnterChannelA(connection->chat, channel, password, &channelCallbacks, piJoinRoomEnterChannelCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* List Group Rooms.
|
|
*******************/
|
|
PEERBool piNewListGroupRoomsOperation
|
|
(
|
|
PEER peer,
|
|
const char * fields,
|
|
peerListGroupRoomsCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(callback);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = connection->listingGroupsOperation = piAddOperation(peer, PI_LIST_GROUP_ROOMS_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Start the listing.
|
|
/////////////////////
|
|
return piSBStartListingGroups(peer, fields);
|
|
}
|
|
|
|
/* Get Player Info.
|
|
*******************/
|
|
static void piGetPlayerInfoCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const char * nick,
|
|
const char * user,
|
|
const char * address,
|
|
void * param
|
|
)
|
|
{
|
|
int profileID = 0;
|
|
unsigned int IP = 0;
|
|
|
|
PEER_CONNECTION_OP;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Check for success.
|
|
/////////////////////
|
|
if(success)
|
|
{
|
|
assert(user);
|
|
assert(user[0]);
|
|
|
|
// Get the info.
|
|
////////////////
|
|
if(!piDemangleUser(user, &IP, &profileID))
|
|
success = CHATFalse;
|
|
|
|
// Cache the info.
|
|
//////////////////
|
|
if(success)
|
|
piSetPlayerIPAndProfileID(peer, nick, IP, profileID);
|
|
}
|
|
if(!success)
|
|
{
|
|
profileID = 0;
|
|
IP = 0;
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
if(operation->callback)
|
|
{
|
|
if(operation->type == PI_GET_PLAYER_INFO_OPERATION)
|
|
piAddGetPlayerInfoCallback(peer, (PEERBool)success, nick, IP, profileID, (peerGetPlayerInfoCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
else if(operation->type == PI_GET_PROFILE_ID_OPERATION)
|
|
piAddGetPlayerProfileIDCallback(peer, (PEERBool)success, nick, profileID, (peerGetPlayerProfileIDCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
else if(operation->type == PI_GET_IP_OPERATION)
|
|
piAddGetPlayerIPCallback(peer, (PEERBool)success, nick, IP, (peerGetPlayerIPCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
else
|
|
assert(0);
|
|
}
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
GSI_UNUSED(address);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piGetPlayerInfoCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const unsigned short * nick,
|
|
const unsigned short * user,
|
|
const unsigned short * address,
|
|
void * param
|
|
)
|
|
{
|
|
char* nick_A = UCS2ToUTF8StringAlloc(nick);
|
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
|
char* address_A = UCS2ToUTF8StringAlloc(address);
|
|
piGetPlayerInfoCallbackA(chat, success, nick_A, user_A, address_A, param);
|
|
gsifree(nick_A);
|
|
gsifree(user_A);
|
|
gsifree(address_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewGetPlayerInfoOperation
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
peerGetPlayerInfoCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_GET_PLAYER_INFO_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Get the user's info.
|
|
///////////////////////
|
|
chatGetBasicUserInfoA(connection->chat, nick, piGetPlayerInfoCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
PEERBool piNewGetProfileIDOperation
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
peerGetPlayerProfileIDCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_GET_PROFILE_ID_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Get the user's info.
|
|
///////////////////////
|
|
chatGetBasicUserInfoA(connection->chat, nick, piGetPlayerInfoCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
PEERBool piNewGetIPOperation
|
|
(
|
|
PEER peer,
|
|
const char * nick,
|
|
peerGetPlayerIPCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(nick);
|
|
assert(nick[0]);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_GET_IP_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Get the user's info.
|
|
///////////////////////
|
|
chatGetBasicUserInfoA(connection->chat, nick, piGetPlayerInfoCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* Change Nick.
|
|
**************/
|
|
static void piChangeNickCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const char * oldNick,
|
|
const char * newNick,
|
|
void * param
|
|
)
|
|
{
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Check for success.
|
|
/////////////////////
|
|
if(success)
|
|
{
|
|
// Update the nick locally.
|
|
///////////////////////////
|
|
strcpy(connection->nick, newNick);
|
|
|
|
#ifdef GSI_UNICODE
|
|
UTF8ToUCS2String(connection->nick, connection->nick_W);
|
|
#endif
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
if(operation->callback)
|
|
piAddChangeNickCallback(peer, (PEERBool)success, oldNick, newNick, (peerChangeNickCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piChangeNickCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const unsigned short * oldNick,
|
|
const unsigned short * newNick,
|
|
void * param
|
|
)
|
|
{
|
|
char* oldNick_A = UCS2ToUTF8StringAlloc(oldNick);
|
|
char* newNick_A = UCS2ToUTF8StringAlloc(newNick);
|
|
piChangeNickCallbackA(chat, success, oldNick_A, newNick_A, param);
|
|
gsifree(oldNick_A);
|
|
gsifree(newNick_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewChangeNickOperation
|
|
(
|
|
PEER peer,
|
|
const char * newNick,
|
|
peerChangeNickCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(newNick);
|
|
assert(newNick[0]);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_CHANGE_NICK_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Change the nick.
|
|
///////////////////
|
|
chatChangeNickA(connection->chat, newNick, piChangeNickCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* Get Global Keys.
|
|
******************/
|
|
static void piGetGlobalKeysCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const char * user,
|
|
int num,
|
|
const char ** keys,
|
|
const char ** values,
|
|
void * param
|
|
)
|
|
{
|
|
int i;
|
|
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Update the watch keys.
|
|
/////////////////////////
|
|
if(success && user)
|
|
{
|
|
for(i = 0 ; i < num ; i++)
|
|
piGlobalKeyChanged(peer, user, keys[i], values[i]);
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
if(operation->callback)
|
|
piAddGetGlobalKeysCallback(peer, (PEERBool)success, user, num, keys, values, (peerGetGlobalKeysCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
if(!success || !user || !operation->num)
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piGetGlobalKeysCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const unsigned short * user,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
const unsigned short ** values,
|
|
void * param
|
|
)
|
|
{
|
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
char** values_A = UCS2ToUTF8StringArrayAlloc(values, num);
|
|
int i;
|
|
piGetGlobalKeysCallbackA(chat, success, user_A, num, (const char**)keys_A, (const char**)values_A, param);
|
|
gsifree(user_A);
|
|
for (i=0; i<num; i++)
|
|
{
|
|
gsifree(keys_A[i]);
|
|
if (values_A != NULL) // may be a NULL when getting keys for "*"
|
|
gsifree(values_A[i]);
|
|
}
|
|
gsifree(keys_A);
|
|
gsifree(values_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewGetGlobalKeysOperation
|
|
(
|
|
PEER peer,
|
|
const char * target,
|
|
int num,
|
|
const char ** keys,
|
|
peerGetGlobalKeysCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(target);
|
|
assert(num > 0);
|
|
assert(keys);
|
|
|
|
if(!target || !target[0])
|
|
return PEERFalse;
|
|
if(num <= 0)
|
|
return PEERFalse;
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_GET_GLOBAL_KEYS_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Use num as a flag for getting a whole channel.
|
|
/////////////////////////////////////////////////
|
|
operation->num = (target[0] == '#');
|
|
|
|
// Get the keys.
|
|
////////////////
|
|
chatGetGlobalKeysA(connection->chat, target, num, keys, piGetGlobalKeysCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* Get Room Keys.
|
|
****************/
|
|
static void piGetChannelKeysCallbackA
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const char * channel,
|
|
const char * user,
|
|
int num,
|
|
const char ** keys,
|
|
const char ** values,
|
|
void * param
|
|
)
|
|
{
|
|
int i;
|
|
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Update the watch keys.
|
|
/////////////////////////
|
|
if(success && user)
|
|
{
|
|
for(i = 0 ; i < num ; i++)
|
|
piRoomKeyChanged(peer, operation->roomType, user, keys[i], values[i]);
|
|
}
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
if(operation->callback)
|
|
piAddGetRoomKeysCallback(peer, (PEERBool)success, operation->roomType, user, num, keys, values, (peerGetRoomKeysCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
if(!success || !user || !operation->num)
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
GSI_UNUSED(channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piGetChannelKeysCallbackW
|
|
(
|
|
CHAT chat,
|
|
CHATBool success,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
const unsigned short ** values,
|
|
void * param
|
|
)
|
|
{
|
|
char* channel_A = UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = UCS2ToUTF8StringAlloc(user);
|
|
char** keys_A = UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
char** values_A = UCS2ToUTF8StringArrayAlloc(values, num);
|
|
int i;
|
|
piGetChannelKeysCallbackA(chat, success, channel_A, user_A, num, (const char**)keys_A, (const char**)values_A, param);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
for (i=0; i<num; i++)
|
|
{
|
|
gsifree(keys_A[i]);
|
|
if (values_A != NULL) // may be a NULL when getting keys for "*"
|
|
gsifree(values_A[i]);
|
|
}
|
|
gsifree(keys_A);
|
|
gsifree(values_A);
|
|
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewGetRoomKeysOperation
|
|
(
|
|
PEER peer,
|
|
RoomType roomType,
|
|
const char * nick,
|
|
int num,
|
|
const char ** keys,
|
|
peerGetRoomKeysCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
ASSERT_ROOMTYPE(roomType);
|
|
assert(num >= 0);
|
|
assert(!num || keys);
|
|
|
|
if(num < 0)
|
|
return PEERFalse;
|
|
if((num > 0) && !keys)
|
|
return PEERFalse;
|
|
|
|
if(!ENTERING_ROOM && !IN_ROOM)
|
|
return PEERFalse;
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_GET_ROOM_KEYS_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
operation->roomType = roomType;
|
|
|
|
// Use num as a flag for getting a whole channel.
|
|
/////////////////////////////////////////////////
|
|
if(nick)
|
|
operation->num = (strcmp(nick, "*") == 0);
|
|
else
|
|
operation->num = 0;
|
|
|
|
// Get the keys.
|
|
////////////////
|
|
chatGetChannelKeysA(connection->chat, ROOM, nick, num, keys, piGetChannelKeysCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* Authenticate CD Key
|
|
*********************/
|
|
static void piAuthenticateCDKeyCallbackA
|
|
(
|
|
CHAT chat,
|
|
int result,
|
|
const char * message,
|
|
void * param
|
|
)
|
|
{
|
|
|
|
PEER_CONNECTION_OP;
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
if(operation->callback)
|
|
piAddAuthenticateCDKeyCallback(peer, result, message, (peerAuthenticateCDKeyCallback)operation->callback, operation->callbackParam, operation->ID);
|
|
|
|
// Remove the operation.
|
|
////////////////////////
|
|
piRemoveOperation(peer, operation);
|
|
|
|
GSI_UNUSED(chat);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void piAuthenticateCDKeyCallbackW
|
|
(
|
|
CHAT chat,
|
|
int result,
|
|
const unsigned short * message,
|
|
void * param
|
|
)
|
|
{
|
|
char* message_A = UCS2ToUTF8StringAlloc(message);
|
|
piAuthenticateCDKeyCallbackA(chat, result, message_A, param);
|
|
gsifree(message_A);
|
|
}
|
|
#endif
|
|
|
|
PEERBool piNewAuthenticateCDKeyOperation
|
|
(
|
|
PEER peer,
|
|
const char * cdkey,
|
|
peerAuthenticateCDKeyCallback callback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
assert(cdkey);
|
|
assert(cdkey[0]);
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_AUTHENTICATE_CDKEY_OPERATION, NULL, (PEERCBType)callback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Check the CD key.
|
|
////////////////////
|
|
chatAuthenticateCDKeyA(connection->chat, cdkey, piAuthenticateCDKeyCallback, operation, CHATFalse);
|
|
|
|
return PEERTrue;
|
|
}
|
|
|
|
/* AutoMatch
|
|
***********/
|
|
PEERBool piNewAutoMatchOperation
|
|
(
|
|
PEER peer,
|
|
SOCKET socket,
|
|
unsigned short port,
|
|
peerAutoMatchStatusCallback statusCallback,
|
|
peerAutoMatchRateCallback rateCallback,
|
|
void * param,
|
|
int opID
|
|
)
|
|
{
|
|
piOperation * operation;
|
|
PEERAutoMatchStatus status;
|
|
|
|
PEER_CONNECTION;
|
|
|
|
// Add the operation.
|
|
/////////////////////
|
|
operation = piAddOperation(peer, PI_AUTO_MATCH_OPERATION, NULL, (PEERCBType)statusCallback, param, opID);
|
|
if(!operation)
|
|
return PEERFalse;
|
|
|
|
// Store the second callback.
|
|
/////////////////////////////
|
|
operation->callback2 = (PEERCBType)rateCallback;
|
|
|
|
// Store the socket and port.
|
|
/////////////////////////////
|
|
operation->socket = socket;
|
|
operation->port = port;
|
|
|
|
// Track this op.
|
|
/////////////////
|
|
connection->autoMatchOperation = operation;
|
|
|
|
// Figure out which status to use.
|
|
//////////////////////////////////
|
|
/* if(connection->inRoom[StagingRoom])
|
|
{
|
|
if(connection->numPlayers[StagingRoom] <= 1)
|
|
{
|
|
if(connection->hosting)
|
|
status = PEERWaiting;
|
|
else
|
|
status = PEERStaging;
|
|
}
|
|
else if(connection->numPlayers[StagingRoom] >= connection->maxPlayers)
|
|
{
|
|
status = PEERReady;
|
|
}
|
|
else
|
|
{
|
|
status = PEERStaging;
|
|
}
|
|
}
|
|
else*/
|
|
{
|
|
status = PEERSearching;
|
|
}
|
|
|
|
// Set the status.
|
|
//////////////////
|
|
piSetAutoMatchStatus(peer, status);
|
|
|
|
return PEERTrue;
|
|
}
|