openmohaa/code/gamespy/Chat/chatc/chatc.c
2023-02-04 21:00:01 +01:00

552 lines
14 KiB
C

// GameSpy Chat SDK C Test App
// Dan "Mr. Pants" Schoenblum
// dan@gamespy.com
/*************
** INCLUDES **
*************/
#include "../chat.h"
#include "../../common/gsStringUtil.h"
#ifdef UNDER_CE
void RetailOutputA(CHAR *tszErr, ...);
#define printf RetailOutputA
#elif defined(_NITRO)
#include "../../common/nitro/screen.h"
#define printf Printf
#define vprintf VPrintf
#endif
#define MAX_MESSAGE_SIZE 200
#define CHAT_NICK_SIZE 128
/************
** GLOBALS **
************/
// mj Nov 7th, zero out to known state globals.
int port = 0;
CHAT chat = {0};
gsi_char serverAddress[128] = {0};
gsi_char chatNick[128] = {0};
gsi_char chatUser[128] = {0};
gsi_char chatName[128] = {0};
gsi_char chatChannel[128] = {0};
gsi_char gamename[128] = {0};
gsi_char secretKey[128] = {0};
CHATBool quit = CHATFalse;
#ifdef __MWERKS__ // CodeWarrior will warn if functions not prototyped
/***************
** PROTOTYPES **
***************/
int test_main(int argc, char **argv);
#endif
/**************
** FUNCTIONS **
**************/
#ifdef GSI_UNICODE
#define _tstrcasecmp WideCaseCompare
#define _tstrncasecmp WideCaseNCompare
#else
#define _tstrcasecmp strcasecmp
#define _tstrncasecmp strncasecmp
#endif
// Simulate case insensitive compare functions
#if defined(GSI_UNICODE)
int WideCaseCompare(const unsigned short* s1, const unsigned short* s2);
int WideCaseNCompare(const unsigned short* s1, const unsigned short* s2, size_t count);
int WideCaseCompare(const unsigned short* s1, const unsigned short* s2)
{
char s1_A[512];
char s2_A[512];
UCS2ToAsciiString(s1, s1_A);
UCS2ToAsciiString(s2, s2_A);
return strcasecmp(s1_A, s2_A);
}
int WideCaseNCompare(const unsigned short* s1, const unsigned short* s2, size_t count)
{
char s1_A[512];
char s2_A[512];
unsigned short temp[512];
// null terminate
temp[count+1] = 0;
// Copy to temp buffer, then convert to ascii
memcpy(temp, s1, count * sizeof(unsigned short));
UCS2ToAsciiString(temp, s1_A);
memcpy(temp, s2, count * sizeof(unsigned short));
UCS2ToAsciiString(temp, s2_A);
return strncasecmp(s1_A, s2_A, count);
}
#endif
static void Raw(CHAT chat, const gsi_char * raw, void * param)
{
_tprintf(_T("RAW: %s\n"), raw);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void Disconnected(CHAT chat, const gsi_char * reason, void * param)
{
_tprintf(_T("Disconnected: %s\n"), reason);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void ChangedNickCallback(CHAT chat, CHATBool success, const gsi_char * oldNick, const gsi_char * newNick, void * param)
{
if(success)
{
_tprintf(_T("Successfully changed"));
_tcscpy(chatNick, newNick);
}
else
_tprintf(_T("Failed to change"));
_tprintf(_T(" nick from %s to %s\n"), oldNick, newNick);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void PrivateMessage(CHAT chat, const gsi_char * user, const gsi_char * message, int type, void * param)
{
_tprintf(_T("Private message from %s: %s\n"), user, message);
// Nick change?
///////////////
if(_tstrncasecmp(_T("nick"), message, 4) == 0)
{
chatChangeNick(chat, &message[5], ChangedNickCallback, NULL, CHATFalse);
}
GSI_UNUSED(type);
GSI_UNUSED(param);
}
static void Invited(CHAT chat, const gsi_char * channel, const gsi_char * user, void * param)
{
_tprintf(_T("Invited by %s to %s\n"), user, channel);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void ChannelMessage(CHAT chat, const gsi_char * channel, const gsi_char * user, const gsi_char * message, int type, void * param)
{
gsi_char buffer[MAX_MESSAGE_SIZE];
_tprintf(_T("%s, in %s, said \"%s\"\n"), user, channel, message);
// Is this from us?
///////////////////
if(_tstrcasecmp(user, chatNick) == 0)
return;
// Is it a command?
///////////////////
if(message[0] == '!')
{
message++;
if(!_tstrcasecmp(message, _T("quit")) || !_tstrcasecmp(message, _T("exit")))
quit = CHATTrue;
return;
}
_tsnprintf(buffer, MAX_MESSAGE_SIZE, _T("%s: I agree"), user);
buffer[MAX_MESSAGE_SIZE - 1] = '\0';
chatSendChannelMessage(chat, channel, buffer, CHAT_MESSAGE);
GSI_UNUSED(type);
GSI_UNUSED(param);
}
static void Kicked(CHAT chat, const gsi_char * channel, const gsi_char * user, const gsi_char * reason, void * param)
{
_tprintf(_T("Kicked from %s by %s: %s\n"), channel, user, reason);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void UserJoined(CHAT chat, const gsi_char * channel, const gsi_char * user, int mode, void * param)
{
_tprintf(_T("%s joined %s"), user, channel);
GSI_UNUSED(chat);
GSI_UNUSED(param);
GSI_UNUSED(mode);
}
static void UserParted(CHAT chat, const gsi_char * channel, const gsi_char * user, int why, const gsi_char * reason, const gsi_char * kicker, void * param)
{
if(why == CHAT_LEFT)
_tprintf(_T("%s left %s\n"), user, channel);
else if(why == CHAT_QUIT)
_tprintf(_T("%s quit: %s\n"), user, reason);
else if(why == CHAT_KICKED)
_tprintf(_T("%s was kicked from %s by %s: %s"), user, channel, kicker, reason);
else if(why == CHAT_KILLED)
_tprintf(_T("%s was killed: %s\n"), user, reason);
else
_tprintf(_T("UserParted() called with unknown part-type\n"));
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void UserChangedNick(CHAT chat, const gsi_char * channel, const gsi_char * oldNick, const gsi_char * newNick, void * param)
{
_tprintf(_T("%s changed nicks to %s\n"), oldNick, newNick);
GSI_UNUSED(chat);
GSI_UNUSED(channel);
GSI_UNUSED(param);
}
static void UserModeChanged(CHAT chat, const gsi_char * channel, const gsi_char * user, int mode, void * param)
{
_tprintf(_T("%s's new mode in %s is "), user, channel);;
if(mode == CHAT_VOICE)
_tprintf(_T("voice\n"));
else if(mode == CHAT_OP)
_tprintf(_T("ops\n"));
else if(mode == (CHAT_VOICE | CHAT_OP))
_tprintf(_T("voice+ops\n"));
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void TopicChanged(CHAT chat, const gsi_char * channel, const gsi_char * topic, void * param)
{
_tprintf(_T("The topic in %s changed to %s\n"), channel, topic);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void ChannelModeChanged(CHAT chat, const gsi_char * channel, CHATChannelMode * mode, void * param)
{
_tprintf(_T("The mode in %s has changed:\n"), channel);
_tprintf(_T(" InviteOnly: %d\n"), mode->InviteOnly);
_tprintf(_T(" Private: %d\n"), mode->Private);
_tprintf(_T(" Secret: %d\n"), mode->Secret);
_tprintf(_T(" Moderated: %d\n"), mode->Moderated);
_tprintf(_T(" NoExternalMessages: %d\n"), mode->NoExternalMessages);
_tprintf(_T(" OnlyOpsChangeTopic: %d\n"), mode->OnlyOpsChangeTopic);
_tprintf(_T(" Limit: "));
if(mode->Limit == 0)
_tprintf(_T("N/A\n"));
else
_tprintf(_T("%d\n"), mode->Limit);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
static void UserListUpdated(CHAT chat, const gsi_char * channel, void * param)
{
_tprintf(_T("User list updated\n"));
GSI_UNUSED(chat);
GSI_UNUSED(channel);
GSI_UNUSED(param);
}
static void ConnectCallback(CHAT chat, CHATBool success, int failureReason, void * param)
{
if (success == CHATFalse)
_tprintf(_T("Failed to connect (%d)\n"), failureReason);
else
_tprintf(_T("Connected\n"));
GSI_UNUSED(chat);
GSI_UNUSED(success);
GSI_UNUSED(param);
}
static void FillInUserCallback(CHAT chat, unsigned int IP, gsi_char user[128], void * param)
{
_tcscpy(user, chatUser);
GSI_UNUSED(chat);
GSI_UNUSED(IP);
GSI_UNUSED(param);
}
static void NickErrorCallback(CHAT chat, int type, const gsi_char * nick, int numSuggestedNicks, const gsi_char ** suggestedNicks, void * param)
{
if(type == CHAT_IN_USE)
{
_tprintf(_T("The nick %s is already being used.\n"), nick);
_tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time());
chatNick[CHAT_NICK_SIZE - 1] = '\0';
chatRetryWithNick(chat, chatNick);
}
else if(type == CHAT_INVALID)
{
_tprintf(_T("The nick %s is invalid!\n"), nick);
// chatDisconnect(chat); THIS CRASHES
// 10-14-2004: Added By Saad Nader
// this is necessary as the function will fail if a new nick is not retries.
////////////////////////////////////////////////////////////////////////////
_tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time());
chatNick[CHAT_NICK_SIZE - 1] = '\0';
chatRetryWithNick(chat, chatNick);
}
else if((type == CHAT_UNIQUENICK_EXPIRED) || (type == CHAT_NO_UNIQUENICK))
{
_tprintf(_T("This account has no uniquenick or an expired uniquenick!\n"));
chatRegisterUniqueNick(chat, 2, _T("MrPants"), _T(""));
}
else if(type == CHAT_INVALID_UNIQUENICK)
{
int i;
_tprintf(_T("The uniquenick %s is invalid or in use\n"), nick);
_tprintf(_T("There are %d suggested nicks:\n"), numSuggestedNicks);
for(i = 0 ; i < numSuggestedNicks ; i++)
_tprintf(_T(" %s\n"), suggestedNicks[i]);
}
// 10-14-2004: Added By Saad Nader
// added for the addition of a new error code.
////////////////////////////////////////////////////////////////////////////
else if(type == CHAT_NICK_TOO_LONG)
{
_tprintf(_T("The nick %s is too long.\n"), nick);
_tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time());
chatNick[CHAT_NICK_SIZE - 1] = '\0';
chatRetryWithNick(chat, chatNick);
}
GSI_UNUSED(param);
}
CHATBool enterChannelSuccess;
static void EnterChannelCallback(CHAT chat, CHATBool success, CHATEnterResult result, const gsi_char * channel, void * param)
{
enterChannelSuccess = success;
GSI_UNUSED(chat);
GSI_UNUSED(result);
GSI_UNUSED(channel);
GSI_UNUSED(param);
}
static void GetUserInfoCallback(CHAT chat, CHATBool success, const gsi_char * nick, const gsi_char * user, const gsi_char * name, const gsi_char * address, int numChannels, const gsi_char ** channels, void * param)
{
int i;
if(!success)
{
_tprintf(_T("GetUserInfo failed\n"));
return;
}
_tprintf(_T("%s's Info:\n"), nick);
_tprintf(_T(" User: %s\n"), user);
_tprintf(_T(" Name: %s\n"), name);
_tprintf(_T(" Address: %s\n"), address);
_tprintf(_T(" Channels (%d):\n"), numChannels);
for(i = 0 ; i < numChannels ; i++)
_tprintf(_T(" %s\n"), channels[i]);
GSI_UNUSED(chat);
GSI_UNUSED(param);
}
/*
static void EnumChannelsAllCallback(CHAT chat, CHATBool success, int numChannels, const gsi_char ** channel, const gsi_char ** topic, int* numUsers, void * param)
{
GSI_UNUSED(chat);
GSI_UNUSED(success);
GSI_UNUSED(numChannels);
GSI_UNUSED(channel);
GSI_UNUSED(topic);
GSI_UNUSED(numUsers);
GSI_UNUSED(param);
}
*/
static void EnumUsersCallback(CHAT chat, CHATBool success, const gsi_char * channel, int numUsers, const gsi_char ** users, int * modes, void * param)
{
int i;
if(!success)
{
_tprintf(_T("EnumUsers failed\n"));
return;
}
for(i = 0 ; i < numUsers ; i++)
chatGetUserInfo(chat, users[i], GetUserInfoCallback, NULL, CHATFalse);
GSI_UNUSED(channel);
GSI_UNUSED(modes);
GSI_UNUSED(param);
}
int test_main(int argc, char **argv)
{
int i;
chatGlobalCallbacks globalCallbacks;
chatChannelCallbacks channelCallbacks;
unsigned long stopTime;
// Set default options.
///////////////////////
// SDK takes care of default server address and port now
//_tcscpy(serverAddress, _T("peerchat." GSI_DOMAIN_NAME));
//port = 6667;
_tsnprintf(chatNick,CHAT_NICK_SIZE,_T("ChatC%lu"),(unsigned long)current_time() % 1000);
chatNick[CHAT_NICK_SIZE - 1] = '\0';
_tcscpy(chatUser, _T("ChatCUser"));
_tcscpy(chatName, _T("ChatCName"));
_tcscpy(chatChannel, _T("#GSP!gmtest"));
_tcscpy(gamename, _T("gmtest"));
secretKey[0] = 'H';
secretKey[1] = 'A';
secretKey[2] = '6';
secretKey[3] = 'z';
secretKey[4] = 'k';
secretKey[5] = 'S';
secretKey[6] = '\0';
// Go through command-line options.
///////////////////////////////////
for(i = 1 ; i < argc ; i++)
{
if((argv[i][0] == '-') && ((i + 1) < argc))
{
switch(argv[i][1])
{
case 's':
#ifndef GSI_UNICODE
strcpy(serverAddress, argv[++i]);
#else
AsciiToUCS2String(argv[++i], serverAddress);
#endif
break;
case 'p':
port = atoi(argv[++i]);
break;
case 'n':
#ifndef GSI_UNICODE
strcpy(chatNick, argv[++i]);
#else
AsciiToUCS2String(argv[++i], chatNick);
#endif
break;
case 'u':
#ifndef GSI_UNICODE
strcpy(chatUser, argv[++i]);
#else
AsciiToUCS2String(argv[++i], chatUser);
#endif
break;
case 'c':
#ifndef GSI_UNICODE
strcpy(chatChannel, argv[++i]);
#else
AsciiToUCS2String(argv[++i], chatChannel);
#endif
break;
default:
_tprintf(_T("Error parsing command-line: %s\n"), argv[i]);
return 1;
}
}
else
{
_tprintf(_T("Error parsing command-line: %s\n"), argv[i]);
return 1;
}
}
// Set global callbacks.
////////////////////////
memset(&globalCallbacks, 0, sizeof(chatGlobalCallbacks));
globalCallbacks.raw = Raw;
globalCallbacks.disconnected = Disconnected;
globalCallbacks.privateMessage = PrivateMessage;
globalCallbacks.invited = Invited;
globalCallbacks.param = NULL;
// Connect.
///////////
chat = chatConnectSecure(serverAddress[0]?serverAddress:NULL, port, chatNick, chatName, gamename, secretKey, &globalCallbacks, NickErrorCallback, FillInUserCallback, ConnectCallback, NULL, CHATTrue);
if(!chat)
{
_tprintf(_T("Connect failed\n"));
return 1;
}
// Set channel callbacks.
/////////////////////////
memset(&channelCallbacks, 0, sizeof(chatChannelCallbacks));
channelCallbacks.channelMessage = ChannelMessage;
channelCallbacks.channelModeChanged = ChannelModeChanged;
channelCallbacks.kicked = Kicked;
channelCallbacks.topicChanged = TopicChanged;
channelCallbacks.userParted = UserParted;
channelCallbacks.userJoined = UserJoined;
channelCallbacks.userListUpdated = UserListUpdated;
channelCallbacks.userModeChanged = UserModeChanged;
channelCallbacks.userChangedNick = UserChangedNick;
channelCallbacks.param = NULL;
// Join.
////////
chatEnterChannel(chat, chatChannel, NULL, &channelCallbacks, EnterChannelCallback, NULL, CHATTrue);
if(!enterChannelSuccess)
{
_tprintf(_T("Enter Channel failed\n"));
return 1;
}
// Say hi.
//////////
chatSendChannelMessage(chat, chatChannel, _T("Hi"), CHAT_MESSAGE);
// Enum through the players.
////////////////////////////
chatEnumUsers(chat, chatChannel, EnumUsersCallback, NULL, CHATFalse);
// Stay for a while.
////////////////////
stopTime = (current_time() + 60000);
do
{
chatThink(chat);
msleep(50);
}
while(!quit && (current_time() < stopTime));
// Say bye.
///////////
chatSendChannelMessage(chat, chatChannel, _T("Bye"), CHAT_MESSAGE);
// Leave.
/////////
chatLeaveChannel(chat, chatChannel, NULL);
// Disconnect.
//////////////
chatDisconnect(chat);
_tprintf(_T("All Done!\n"));
return 0;
}