mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
3075 lines
71 KiB
C
3075 lines
71 KiB
C
/*
|
|
GameSpy Chat SDK
|
|
Dan "Mr. Pants" Schoenblum
|
|
dan@gamespy.com
|
|
|
|
Copyright 1999-2007 GameSpy Industries, Inc
|
|
|
|
devsupport@gamespy.com
|
|
*/
|
|
|
|
/*************
|
|
** INCLUDES **
|
|
*************/
|
|
#include "chat.h"
|
|
#include "chatMain.h"
|
|
#include "chatASCII.h"
|
|
#include "chatSocket.h"
|
|
#include "chatHandlers.h"
|
|
#include "chatChannel.h"
|
|
#include "chatCallbacks.h"
|
|
|
|
|
|
#if defined(_WIN32)
|
|
// Silence the warning about explicitly casting a function* to a void*
|
|
#pragma warning(disable:4054)
|
|
#endif
|
|
|
|
/************
|
|
** GLOBALS **
|
|
************/
|
|
// This can be overridden using an extern to pass a different versionID number to the chat server as part of the crypt negotiation
|
|
int ciVersionID = 1;
|
|
|
|
/************
|
|
** DEFINES **
|
|
************/
|
|
#define CI_DO_BLOCKING if(blocking)\
|
|
{\
|
|
do{\
|
|
ciThink(chat, ID);\
|
|
msleep(10);\
|
|
}while(ciCheckForID(chat, ID));\
|
|
}
|
|
|
|
#define ASSERT_CHANNEL() assert(channel != NULL); assert(channel[0] != '\0');
|
|
#define ASSERT_NICK() assert(nick != NULL); assert(nick[0] != '\0'); assert(strlen(nick) < MAX_NICK);
|
|
#define ASSERT_USER(user) assert(user != NULL); assert(user[0] != '\0'); assert(strlen(user) < MAX_USER);
|
|
#define ASSERT_MESSAGE() assert(message != NULL); assert(message[0] != '\0');
|
|
#define ASSERT_TYPE(type) assert((type == CHAT_MESSAGE) || (type == CHAT_ACTION) || (type == CHAT_NOTICE) || (type == CHAT_UTM) || (type == CHAT_ATM));
|
|
#define ASSERT_PASSWORD() assert(password != NULL); assert(password[0] != '\0');
|
|
#define ASSERT_BAN() assert(ban != NULL); assert(ban [0] != '\0');
|
|
|
|
#define CI_NUM_TRANSLATED_NICKS 2
|
|
|
|
/**********
|
|
** TYPES **
|
|
**********/
|
|
|
|
typedef struct ciEnumUsersData
|
|
{
|
|
chatEnumUsersCallback callback;
|
|
void * param;
|
|
} ciEnumUsersData;
|
|
|
|
/**************
|
|
** FUNCTIONS **
|
|
**************/
|
|
static CHATBool ciProcessServerMessage(CHAT chat, const ciServerMessage * message)
|
|
{
|
|
int i;
|
|
|
|
assert(message != NULL);
|
|
|
|
// Figure out what type of message this is.
|
|
///////////////////////////////////////////
|
|
for(i = 0 ; i < numServerMessageTypes ; i++)
|
|
{
|
|
// Does the type match?
|
|
///////////////////////
|
|
if(strcasecmp(message->command, serverMessageTypes[i].command) == 0)
|
|
{
|
|
// Is there a handler?
|
|
//////////////////////
|
|
if(serverMessageTypes[i].handler != NULL)
|
|
{
|
|
// Call the handler.
|
|
////////////////////
|
|
serverMessageTypes[i].handler(chat, message);
|
|
}
|
|
|
|
return CHATTrue;
|
|
}
|
|
}
|
|
|
|
// Didn't find a match.
|
|
///////////////////////
|
|
return CHATFalse; //ERRCON
|
|
}
|
|
|
|
static CHATBool ciCheckForID(CHAT chat, int ID)
|
|
{
|
|
return (CHATBool)(ciCheckFiltersForID(chat, ID) || ciCheckCallbacksForID(chat, ID));
|
|
}
|
|
|
|
void ciHandleDisconnect(CHAT chat, const char * reason)
|
|
{
|
|
CHATBool connecting;
|
|
CONNECTION;
|
|
|
|
// Check if we've already handled this.
|
|
///////////////////////////////////////
|
|
if(connection->disconnected)
|
|
return;
|
|
|
|
// Keep track of if we are trying to connect.
|
|
/////////////////////////////////////////////
|
|
connecting = connection->connecting;
|
|
|
|
// Not connected anymore.
|
|
/////////////////////////
|
|
connection->connected = CHATFalse;
|
|
connection->connecting = CHATFalse;
|
|
connection->disconnected = CHATTrue;
|
|
|
|
// If we're still connecting, let the app know the attempt failed.
|
|
//////////////////////////////////////////////////////////////////
|
|
if(connection->connecting)
|
|
{
|
|
// Call the callback.
|
|
/////////////////////
|
|
if(connection->connectCallback != NULL)
|
|
connection->connectCallback(chat, CHATFalse, CHAT_DISCONNECTED, connection->connectParam);
|
|
}
|
|
// Otherwise call the global callback.
|
|
//////////////////////////////////////
|
|
else if(connection->globalCallbacks.disconnected != NULL)
|
|
{
|
|
ciCallbackDisconnectedParams params;
|
|
params.reason = (char *)reason;
|
|
ciAddCallback(chat, CALLBACK_DISCONNECTED, (void*)connection->globalCallbacks.disconnected, ¶ms, connection->globalCallbacks.param, 0, NULL);
|
|
}
|
|
GSI_UNUSED(connecting);
|
|
}
|
|
|
|
static void ciThink(CHAT chat, int ID)
|
|
{
|
|
ciServerMessage * message;
|
|
CONNECTION;
|
|
|
|
// Is the socket connected?
|
|
///////////////////////////
|
|
if(connection->chatSocket.connectState == ciConnected)
|
|
{
|
|
// Do processing.
|
|
/////////////////
|
|
ciSocketThink(&connection->chatSocket);
|
|
|
|
// Check received messages.
|
|
///////////////////////////
|
|
while((message = ciSocketRecv(&connection->chatSocket)) != NULL)
|
|
{
|
|
// Call the raw callback.
|
|
/////////////////////////
|
|
if(connection->globalCallbacks.raw != NULL)
|
|
{
|
|
ciCallbackRawParams params;
|
|
params.raw = message->message;
|
|
ciAddCallback(chat, CALLBACK_RAW, (void*)connection->globalCallbacks.raw, ¶ms, connection->globalCallbacks.param, 0, NULL);
|
|
}
|
|
|
|
// Process the message.
|
|
///////////////////////
|
|
ciProcessServerMessage(chat, message);
|
|
}
|
|
|
|
// Have we lost connection?
|
|
///////////////////////////
|
|
if(connection->chatSocket.connectState == ciDisconnected)
|
|
{
|
|
ciHandleDisconnect(chat, "Disconnected");
|
|
}
|
|
}
|
|
|
|
// Let the filters think.
|
|
/////////////////////////
|
|
ciFilterThink(chat);
|
|
|
|
// Call callbacks.
|
|
//////////////////
|
|
ciCallCallbacks(chat, ID);
|
|
|
|
}
|
|
|
|
/************
|
|
** GENERAL **
|
|
************/
|
|
void ciSendNick(CHAT chat)
|
|
{
|
|
const char * nick;
|
|
CONNECTION;
|
|
|
|
// Handle based on login type.
|
|
//////////////////////////////
|
|
if(connection->loginType == CINoLogin)
|
|
{
|
|
|
|
// 10-13-2004: changed by Saad Nader
|
|
// check for nick length and for an invalid nick.
|
|
/////////////////////////////////////////////////
|
|
|
|
int validateNick = ciNickIsValid(connection->nick);
|
|
if (validateNick != CHAT_NICK_OK)
|
|
{
|
|
ciNickError(chat, validateNick, connection->nick, 0, NULL);
|
|
return;
|
|
}
|
|
|
|
// Use the provided nick.
|
|
/////////////////////////
|
|
nick = connection->nick;
|
|
}
|
|
else if((connection->loginType == CIProfileLogin) && (connection->namespaceID == 0))
|
|
{
|
|
|
|
// 10-13-2004: changed by Saad Nader
|
|
// check for nick length and for an invalid nick.
|
|
/////////////////////////////////////////////////
|
|
|
|
int validateNick = ciNickIsValid(connection->profilenick);
|
|
if (validateNick != CHAT_NICK_OK)
|
|
{
|
|
ciNickError(chat, validateNick, connection->profilenick, 0, NULL);
|
|
return;
|
|
}
|
|
|
|
// Use the profile's nick.
|
|
//////////////////////////
|
|
nick = connection->profilenick;
|
|
}
|
|
else
|
|
{
|
|
// The server will use the uniquenick.
|
|
//////////////////////////////////////
|
|
nick = "*";
|
|
}
|
|
|
|
// Send the nick.
|
|
/////////////////
|
|
ciSocketSendf(&connection->chatSocket, "NICK %s", nick);
|
|
}
|
|
|
|
void ciSendUser(CHAT chat)
|
|
{
|
|
CONNECTION;
|
|
|
|
// Send the user.
|
|
/////////////////
|
|
ciSocketSendf(&connection->chatSocket, "USER %s %s %s :%s",
|
|
connection->user,
|
|
"127.0.0.1",
|
|
connection->server,
|
|
connection->name);
|
|
}
|
|
|
|
void ciSendNickAndUser(CHAT chat)
|
|
{
|
|
ciSendUser(chat);
|
|
ciSendNick(chat);
|
|
}
|
|
|
|
void ciSendLogin(CHAT chat)
|
|
{
|
|
char passwordHash[33];
|
|
CONNECTION;
|
|
|
|
// If it's pre-auth, send it.
|
|
/////////////////////////////
|
|
if(connection->loginType == CIPreAuthLogin)
|
|
{
|
|
ciSocketSendf(&connection->chatSocket, "LOGINPREAUTH %s %s",
|
|
connection->authtoken,
|
|
connection->partnerchallenge);
|
|
|
|
return;
|
|
}
|
|
|
|
// For uniquenick or profile logins, we need to MD5 the password.
|
|
/////////////////////////////////////////////////////////////////
|
|
MD5Digest((unsigned char *)connection->password, strlen(connection->password), passwordHash);
|
|
|
|
// Send the login message based on type.
|
|
////////////////////////////////////////
|
|
if(connection->loginType == CIUniqueNickLogin)
|
|
{
|
|
ciSocketSendf(&connection->chatSocket, "LOGIN %d %s %s",
|
|
connection->namespaceID,
|
|
connection->uniquenick,
|
|
passwordHash);
|
|
}
|
|
else if(connection->loginType == CIProfileLogin)
|
|
{
|
|
ciSocketSendf(&connection->chatSocket, "LOGIN %d * %s :%s@%s",
|
|
connection->namespaceID,
|
|
passwordHash,
|
|
connection->profilenick,
|
|
connection->email);
|
|
}
|
|
else
|
|
{
|
|
// If we get here, the login type is invalid or isn't being handled properly.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
static CHAT chatConnectDoit(CILoginType loginType,
|
|
const char * serverAddress,
|
|
int port,
|
|
const char * nick,
|
|
const char * user,
|
|
const char * name,
|
|
int namespaceID,
|
|
const char * email,
|
|
const char * profilenick,
|
|
const char * uniquenick,
|
|
const char * password,
|
|
const char * authtoken,
|
|
const char * partnerchallenge,
|
|
const char * gamename,
|
|
const char * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
ciConnection * connection;
|
|
const char * socketNick = "";
|
|
|
|
//Added default server address and port
|
|
//assert(serverAddress != NULL);
|
|
assert(callbacks != NULL);
|
|
assert(connectCallback != NULL);
|
|
|
|
// Check the arguments based on the login type.
|
|
///////////////////////////////////////////////
|
|
if(loginType == CINoLogin)
|
|
{
|
|
ASSERT_NICK();
|
|
if(!nick || !nick[0])
|
|
return NULL;
|
|
socketNick = nick;
|
|
}
|
|
else if(loginType == CIUniqueNickLogin)
|
|
{
|
|
assert(namespaceID > 0);
|
|
if(namespaceID <= 0)
|
|
return NULL;
|
|
assert(uniquenick && uniquenick[0]);
|
|
if(!uniquenick || !uniquenick[0])
|
|
return NULL;
|
|
assert(password && password[0]);
|
|
if(!password || !password[0])
|
|
return NULL;
|
|
socketNick = uniquenick;
|
|
}
|
|
else if(loginType == CIProfileLogin)
|
|
{
|
|
assert(namespaceID >= 0);
|
|
if(namespaceID < 0)
|
|
return NULL;
|
|
assert(email && email[0]);
|
|
if(!email || !email[0])
|
|
return NULL;
|
|
assert(profilenick && profilenick[0]);
|
|
if(!profilenick || !profilenick[0])
|
|
return NULL;
|
|
assert(password && password[0]);
|
|
if(!password || !password[0])
|
|
return NULL;
|
|
socketNick = profilenick;
|
|
}
|
|
else if(loginType == CIPreAuthLogin)
|
|
{
|
|
assert(authtoken && authtoken[0]);
|
|
if(!authtoken || !authtoken[0])
|
|
return NULL;
|
|
assert(partnerchallenge && partnerchallenge[0]);
|
|
if(!partnerchallenge || !partnerchallenge[0])
|
|
return NULL;
|
|
socketNick = "preauth";
|
|
}
|
|
if(loginType != CINoLogin)
|
|
{
|
|
assert(gamename && gamename[0]);
|
|
if(!gamename || !gamename[0])
|
|
return NULL;
|
|
assert(secretKey && secretKey[0]);
|
|
if(!secretKey || !secretKey[0])
|
|
return NULL;
|
|
}
|
|
|
|
// Init sockets.
|
|
////////////////
|
|
SocketStartUp();
|
|
|
|
// Create a connection object.
|
|
//////////////////////////////
|
|
connection = (ciConnection *)gsimalloc(sizeof(ciConnection));
|
|
if(connection == NULL)
|
|
return NULL; //ERRCON
|
|
|
|
// Initialize the connection.
|
|
/////////////////////////////
|
|
memset(connection, 0, sizeof(ciConnection));
|
|
connection->loginType = loginType;
|
|
if(nick)
|
|
strzcpy(connection->nick, nick, MAX_NICK);
|
|
if(user)
|
|
strzcpy(connection->user, user, MAX_USER);
|
|
#ifdef GSI_UNICODE // store a unicode version of the nick and user
|
|
UTF8ToUCS2String(connection->nick, connection->nickW);
|
|
UTF8ToUCS2String(connection->user, connection->userW);
|
|
#endif
|
|
if(name)
|
|
strzcpy(connection->name, name, MAX_NAME);
|
|
connection->namespaceID = namespaceID;
|
|
if(email)
|
|
strzcpy(connection->email, email, MAX_EMAIL);
|
|
if(profilenick)
|
|
strzcpy(connection->profilenick, profilenick, MAX_PROFILENICK);
|
|
if(uniquenick)
|
|
strzcpy(connection->uniquenick, uniquenick, MAX_UNIQUENICK);
|
|
if(password)
|
|
strzcpy(connection->password, password, MAX_PASSWORD);
|
|
if(authtoken)
|
|
strzcpy(connection->authtoken, authtoken, MAX_AUTHTOKEN);
|
|
if(partnerchallenge)
|
|
strzcpy(connection->partnerchallenge, partnerchallenge, MAX_PARTNERCHALLENGE);
|
|
strzcpy(connection->server, serverAddress?serverAddress:CI_DEFAULT_SERVER_ADDRESS, MAX_SERVER);
|
|
connection->port = port?port:CI_DEFUILT_SERVER_PORT;
|
|
connection->globalCallbacks = *callbacks;
|
|
connection->nextID = 1;
|
|
connection->connecting = CHATTrue;
|
|
connection->quiet = CHATFalse;
|
|
|
|
// Initialize the channel table.
|
|
////////////////////////////////
|
|
if(!ciInitChannels(connection))
|
|
{
|
|
gsifree(connection);
|
|
SocketShutDown();
|
|
return NULL; //ERRCON
|
|
}
|
|
|
|
// Initialize the callbacks list.
|
|
/////////////////////////////////
|
|
if(!ciInitCallbacks(connection))
|
|
{
|
|
ciCleanupChannels((CHAT)connection);
|
|
gsifree(connection);
|
|
SocketShutDown();
|
|
return NULL; //ERRCON
|
|
}
|
|
|
|
// Initialize the socket.
|
|
/////////////////////////
|
|
if(!ciSocketInit(&connection->chatSocket, socketNick))
|
|
{
|
|
ciCleanupCallbacks((CHAT)connection);
|
|
ciCleanupChannels((CHAT)connection);
|
|
gsifree(connection);
|
|
SocketShutDown();
|
|
return NULL; //ERRCON
|
|
}
|
|
|
|
// Connect the socket.
|
|
//////////////////////
|
|
if(!ciSocketConnect(&connection->chatSocket, connection->server, connection->port))
|
|
{
|
|
ciSocketDisconnect(&connection->chatSocket);
|
|
ciCleanupCallbacks((CHAT)connection);
|
|
ciCleanupChannels((CHAT)connection);
|
|
gsifree(connection);
|
|
SocketShutDown();
|
|
return NULL; //ERRCON
|
|
}
|
|
|
|
// Special stuff for MS Chat server.
|
|
////////////////////////////////////
|
|
//ciSocketSend(&connection->chatSocket, "MODE ISIRCX");
|
|
//ciSocketSend(&connection->chatSocket, "IRCX");
|
|
|
|
// Set the callback info.
|
|
/////////////////////////
|
|
connection->nickErrorCallback = nickErrorCallback;
|
|
connection->fillInUserCallback = fillInUserCallback;
|
|
connection->connectCallback = connectCallback;
|
|
connection->connectParam = param;
|
|
|
|
// Check for a secure connection.
|
|
/////////////////////////////////
|
|
if(gamename && gamename[0] && secretKey && secretKey[0])
|
|
{
|
|
// Save the game secret key.
|
|
////////////////////////////
|
|
strzcpy(connection->secretKey, secretKey, MAX_SECRETKEY);
|
|
|
|
// Get the random keys.
|
|
///////////////////////
|
|
ciSocketSendf(&connection->chatSocket, "CRYPT des %d %s", ciVersionID, gamename);
|
|
}
|
|
else if(connection->fillInUserCallback)
|
|
{
|
|
// Get the IP.
|
|
//////////////
|
|
ciSocketSend(&connection->chatSocket, "USRIP");
|
|
}
|
|
else
|
|
{
|
|
// Send the nick and user.
|
|
//////////////////////////
|
|
ciSendNickAndUser((CHAT)connection);
|
|
}
|
|
|
|
// Do blocking.
|
|
///////////////
|
|
if(blocking)
|
|
{
|
|
// While we're connecting.
|
|
//////////////////////////
|
|
do
|
|
{
|
|
ciThink((CHAT)connection, 0);
|
|
msleep(10);
|
|
} while(connection->connecting);
|
|
|
|
// Check if the connect failed.
|
|
///////////////////////////////
|
|
if(!connection->connected)
|
|
{
|
|
// Disconnect the connection.
|
|
/////////////////////////////
|
|
chatDisconnect((CHAT)connection);
|
|
connection = NULL;
|
|
}
|
|
}
|
|
|
|
return (CHAT)connection;
|
|
}
|
|
|
|
CHAT chatConnectA(const char * serverAddress,
|
|
int port,
|
|
const char * nick,
|
|
const char * user,
|
|
const char * name,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
return chatConnectDoit(CINoLogin,
|
|
serverAddress,
|
|
port,
|
|
nick,
|
|
user,
|
|
name,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
callbacks,
|
|
nickErrorCallback,
|
|
NULL,
|
|
connectCallback,
|
|
param,
|
|
blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHAT chatConnectW(const unsigned short * serverAddress,
|
|
int port,
|
|
const unsigned short * nick,
|
|
const unsigned short * user,
|
|
const unsigned short * name,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress);
|
|
char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
char* name_A = (char*)UCS2ToUTF8StringAlloc(name);
|
|
|
|
CHAT aChat = chatConnectA(serverAddress_A,
|
|
port,
|
|
nick_A,
|
|
user_A,
|
|
name_A,
|
|
callbacks,
|
|
nickErrorCallback,
|
|
connectCallback,
|
|
param,
|
|
blocking);
|
|
|
|
gsifree(serverAddress_A);
|
|
gsifree(nick_A);
|
|
gsifree(user_A);
|
|
gsifree(name_A);
|
|
|
|
return aChat;
|
|
}
|
|
#endif
|
|
|
|
CHAT chatConnectSpecialA(const char * serverAddress,
|
|
int port,
|
|
const char * nick,
|
|
const char * name,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
return chatConnectDoit(CINoLogin,
|
|
serverAddress,
|
|
port,
|
|
nick,
|
|
NULL,
|
|
name,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
callbacks,
|
|
nickErrorCallback,
|
|
fillInUserCallback,
|
|
connectCallback,
|
|
param,
|
|
blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHAT chatConnectSpecialW(const unsigned short * serverAddress,
|
|
int port,
|
|
const unsigned short * nick,
|
|
const unsigned short * name,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress);
|
|
char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick);
|
|
char* name_A = (char*)UCS2ToUTF8StringAlloc(name);
|
|
CHAT aChat = chatConnectSpecialA(serverAddress_A, port, nick_A, name_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking);
|
|
gsifree(serverAddress_A);
|
|
gsifree(nick_A);
|
|
gsifree(name_A);
|
|
|
|
return aChat;
|
|
}
|
|
#endif
|
|
|
|
CHAT chatConnectSecureA(const char * serverAddress,
|
|
int port,
|
|
const char * nick,
|
|
const char * name,
|
|
const char * gamename,
|
|
const char * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
return chatConnectDoit(CINoLogin,
|
|
serverAddress,
|
|
port,
|
|
nick,
|
|
NULL,
|
|
name,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
gamename,
|
|
secretKey,
|
|
callbacks,
|
|
nickErrorCallback,
|
|
fillInUserCallback,
|
|
connectCallback,
|
|
param,
|
|
blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHAT chatConnectSecureW(const unsigned short * serverAddress,
|
|
int port,
|
|
const unsigned short * nick,
|
|
const unsigned short * name,
|
|
const unsigned short * gamename,
|
|
const unsigned short * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress);
|
|
char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick);
|
|
char* name_A = (char*)UCS2ToUTF8StringAlloc(name);
|
|
char* gamename_A = (char*)UCS2ToUTF8StringAlloc(gamename);
|
|
char* secretKey_A = (char*)UCS2ToUTF8StringAlloc(secretKey);
|
|
CHAT aChat = chatConnectSecureA(serverAddress_A, port, nick_A, name_A, gamename_A, secretKey_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking);
|
|
gsifree(serverAddress_A);
|
|
gsifree(nick_A);
|
|
gsifree(name_A);
|
|
gsifree(gamename_A);
|
|
gsifree(secretKey_A);
|
|
|
|
return aChat;
|
|
}
|
|
#endif
|
|
|
|
CHAT chatConnectLoginA(const char * serverAddress,
|
|
int port,
|
|
int namespaceID,
|
|
const char * email,
|
|
const char * profilenick,
|
|
const char * uniquenick,
|
|
const char * password,
|
|
const char * name,
|
|
const char * gamename,
|
|
const char * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
return chatConnectDoit((uniquenick && uniquenick[0])?CIUniqueNickLogin:CIProfileLogin,
|
|
serverAddress,
|
|
port,
|
|
NULL,
|
|
NULL,
|
|
name,
|
|
namespaceID,
|
|
email,
|
|
profilenick,
|
|
uniquenick,
|
|
password,
|
|
NULL,
|
|
NULL,
|
|
gamename,
|
|
secretKey,
|
|
callbacks,
|
|
nickErrorCallback,
|
|
fillInUserCallback,
|
|
connectCallback,
|
|
param,
|
|
blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHAT chatConnectLoginW(const unsigned short * serverAddress,
|
|
int port,
|
|
int namespaceID,
|
|
const unsigned short * email,
|
|
const unsigned short * profilenick,
|
|
const unsigned short * uniquenick,
|
|
const unsigned short * password,
|
|
const unsigned short * name,
|
|
const unsigned short * gamename,
|
|
const unsigned short * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress);
|
|
char* email_A = (char*)UCS2ToUTF8StringAlloc(email);
|
|
char* profilenick_A = (char*)UCS2ToUTF8StringAlloc(profilenick);
|
|
char* uniquenick_A = (char*)UCS2ToUTF8StringAlloc(uniquenick);
|
|
char* password_A = (char*)UCS2ToUTF8StringAlloc(password);
|
|
char* name_A = (char*)UCS2ToUTF8StringAlloc(name);
|
|
char* gamename_A = (char*)UCS2ToUTF8StringAlloc(gamename);
|
|
char* secretKey_A = (char*)UCS2ToUTF8StringAlloc(secretKey);
|
|
CHAT aChat= chatConnectLoginA(serverAddress_A, port, namespaceID, email_A, profilenick_A, uniquenick_A, password_A, name_A, gamename_A, secretKey_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking);
|
|
gsifree(serverAddress_A);
|
|
gsifree(email_A);
|
|
gsifree(profilenick_A);
|
|
gsifree(uniquenick_A);
|
|
gsifree(name_A);
|
|
gsifree(gamename_A);
|
|
gsifree(secretKey_A);
|
|
|
|
return aChat;
|
|
}
|
|
#endif
|
|
|
|
CHAT chatConnectPreAuthA(const char * serverAddress,
|
|
int port,
|
|
const char * authtoken,
|
|
const char * partnerchallenge,
|
|
const char * name,
|
|
const char * gamename,
|
|
const char * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
return chatConnectDoit(CIPreAuthLogin,
|
|
serverAddress,
|
|
port,
|
|
NULL,
|
|
NULL,
|
|
name,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
authtoken,
|
|
partnerchallenge,
|
|
gamename,
|
|
secretKey,
|
|
callbacks,
|
|
nickErrorCallback,
|
|
fillInUserCallback,
|
|
connectCallback,
|
|
param,
|
|
blocking);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHAT chatConnectPreAuthW(const unsigned short * serverAddress,
|
|
int port,
|
|
const unsigned short * authtoken,
|
|
const unsigned short * partnerchallenge,
|
|
const unsigned short * name,
|
|
const unsigned short * gamename,
|
|
const unsigned short * secretKey,
|
|
chatGlobalCallbacks * callbacks,
|
|
chatNickErrorCallback nickErrorCallback,
|
|
chatFillInUserCallback fillInUserCallback,
|
|
chatConnectCallback connectCallback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* serverAddress_A = (char*)UCS2ToUTF8StringAlloc(serverAddress);
|
|
char* authtoken_A = (char*)UCS2ToUTF8StringAlloc(authtoken);
|
|
char* partnerchallenge_A = (char*)UCS2ToUTF8StringAlloc(partnerchallenge);
|
|
char* name_A = (char*)UCS2ToUTF8StringAlloc(name);
|
|
char* gamename_A = (char*)UCS2ToUTF8StringAlloc(gamename);
|
|
char* secretKey_A = (char*)UCS2ToUTF8StringAlloc(secretKey);
|
|
CHAT aChat = chatConnectPreAuthA(serverAddress_A, port, authtoken_A, partnerchallenge_A, name_A, gamename_A, secretKey_A, callbacks, nickErrorCallback, fillInUserCallback, connectCallback, param, blocking);
|
|
gsifree(serverAddress_A);
|
|
gsifree(authtoken_A);
|
|
gsifree(partnerchallenge_A);
|
|
gsifree(name_A);
|
|
gsifree(gamename_A);
|
|
gsifree(secretKey_A);
|
|
|
|
return aChat;
|
|
}
|
|
#endif
|
|
|
|
void chatRetryWithNickA(CHAT chat,
|
|
const char * nick)
|
|
{
|
|
int validateNick;
|
|
CONNECTION;
|
|
|
|
// Are we already connected?
|
|
////////////////////////////
|
|
if(connection->connected)
|
|
return;
|
|
|
|
// A NULL nick means stop retrying and disconnect
|
|
if (nick == NULL)
|
|
{
|
|
connection->connecting = CHATFalse;
|
|
|
|
// Call the callback. (Failed to connect)
|
|
/////////////////////
|
|
if(connection->connectCallback != NULL)
|
|
connection->connectCallback(chat, CHATFalse, CHAT_NICK_ERROR, connection->connectParam);
|
|
|
|
return;
|
|
}
|
|
|
|
// Copy the new nick.
|
|
/////////////////////
|
|
strzcpy(connection->nick, nick, MAX_NICK);
|
|
#ifdef GSI_UNICODE // store a unicode version of the nick
|
|
AsciiToUCS2String(connection->nick, connection->nickW);
|
|
#endif
|
|
|
|
// Check for a bad nick.
|
|
////////////////////////
|
|
validateNick = ciNickIsValid(nick);
|
|
if (validateNick != CHAT_NICK_OK)
|
|
{
|
|
ciNickError(chat, validateNick, nick, 0, NULL);
|
|
return;
|
|
}
|
|
|
|
// Send the new nick.
|
|
/////////////////////
|
|
ciSocketSendf(&connection->chatSocket, "NICK :%s", nick);
|
|
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatRetryWithNickW(CHAT chat,
|
|
const unsigned short * nick)
|
|
{
|
|
char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick);
|
|
chatRetryWithNickA(chat, nick_A);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
void chatRegisterUniqueNickA(CHAT chat,
|
|
int namespaceID,
|
|
const char * uniquenick,
|
|
const char * cdkey)
|
|
{
|
|
CONNECTION;
|
|
|
|
// Are we already connected?
|
|
////////////////////////////
|
|
if(connection->connected)
|
|
return;
|
|
|
|
// A NULL nick means stop trying and disconnect.
|
|
////////////////////////////////////////////////
|
|
if(uniquenick == NULL)
|
|
{
|
|
connection->connecting = CHATFalse;
|
|
|
|
// Call the callback.
|
|
/////////////////////
|
|
if(connection->connectCallback != NULL)
|
|
connection->connectCallback(chat, CHATFalse, CHAT_NICK_ERROR, connection->connectParam);
|
|
|
|
return;
|
|
}
|
|
|
|
// CDKey is optional.
|
|
/////////////////////
|
|
if(!cdkey)
|
|
cdkey = "";
|
|
|
|
// Send the message.
|
|
////////////////////
|
|
ciSocketSendf(&connection->chatSocket, "REGISTERNICK %d %s %s", namespaceID, uniquenick, cdkey);
|
|
|
|
// Save the uniquenick we're trying to use.
|
|
///////////////////////////////////////////
|
|
strzcpy(connection->uniquenick, uniquenick, MAX_UNIQUENICK);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatRegisterUniqueNickW(CHAT chat,
|
|
int namespaceID,
|
|
const unsigned short * uniquenick,
|
|
const unsigned short * cdkey)
|
|
{
|
|
char* uniquenick_A = (char*)UCS2ToUTF8StringAlloc(uniquenick);
|
|
char* cdkey_A = (char*)UCS2ToUTF8StringAlloc(cdkey);
|
|
chatRegisterUniqueNickA(chat, namespaceID, uniquenick_A, cdkey_A);
|
|
gsifree(uniquenick_A);
|
|
gsifree(cdkey_A);
|
|
}
|
|
#endif
|
|
|
|
void chatDisconnect(CHAT chat)
|
|
{
|
|
CONNECTION;
|
|
|
|
// Cleanup all the filters first.
|
|
/////////////////////////////////
|
|
ciCleanupFilters(chat);
|
|
|
|
// Call the disconnected callback if we haven't already.
|
|
////////////////////////////////////////////////////////
|
|
if(!connection->disconnected && connection->globalCallbacks.disconnected)
|
|
#ifdef GSI_UNICODE
|
|
connection->globalCallbacks.disconnected(chat, L"", connection->globalCallbacks.param);
|
|
#else
|
|
connection->globalCallbacks.disconnected(chat, "", connection->globalCallbacks.param);
|
|
#endif
|
|
|
|
// Are we connected.
|
|
////////////////////
|
|
if(connection->connected)
|
|
{
|
|
ciSocketSend(&connection->chatSocket, "QUIT :Later!");
|
|
ciSocketThink(&connection->chatSocket);
|
|
}
|
|
|
|
// gsifree the channel table.
|
|
//////////////////////////
|
|
ciCleanupChannels(chat);
|
|
|
|
// Cleanup the callbacks list.
|
|
//////////////////////////////
|
|
ciCleanupCallbacks(chat);
|
|
|
|
// Shutdown the chat socket.
|
|
////////////////////////////
|
|
ciSocketDisconnect(&connection->chatSocket);
|
|
|
|
// gsifree the memory.
|
|
///////////////////
|
|
gsifree(chat);
|
|
|
|
// Shutdown sockets.
|
|
////////////////////
|
|
SocketShutDown();
|
|
}
|
|
|
|
void chatThink(CHAT chat)
|
|
{
|
|
ciThink(chat, 0);
|
|
}
|
|
|
|
void chatSendRawA(CHAT chat,
|
|
const char * command)
|
|
{
|
|
CONNECTION;
|
|
if(!connection || (!connection->connected && !connection->connecting))
|
|
return;
|
|
|
|
ciSocketSend(&connection->chatSocket, command);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSendRawW(CHAT chat,
|
|
const unsigned short* command)
|
|
{
|
|
char* command_A = (char*)UCS2ToUTF8StringAlloc(command);
|
|
chatSendRawA(chat, command_A);
|
|
gsifree(command_A);
|
|
}
|
|
#endif
|
|
|
|
void chatChangeNickA(CHAT chat,
|
|
const char * newNick,
|
|
chatChangeNickCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CHATBool success = CHATTrue;
|
|
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
assert(newNick);
|
|
assert(newNick[0]);
|
|
assert(strlen(newNick) < MAX_NICK);
|
|
assert(callback);
|
|
assert(connection->connected);
|
|
|
|
// chatRetryWithNick should be called while connecting.
|
|
///////////////////////////////////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// No nick.
|
|
///////////
|
|
if(!newNick || !newNick[0])
|
|
success = CHATFalse;
|
|
|
|
// 10-13-2004: Added By Saad Nader
|
|
// check for long or invalid chars in new nick.
|
|
///////////////////////////////////////////////
|
|
if (ciNickIsValid(newNick) != CHAT_NICK_OK)
|
|
{
|
|
success = CHATFalse;
|
|
}
|
|
|
|
// Check for same nick.
|
|
///////////////////////
|
|
if(success && (strcasecmp(newNick, connection->nick) == 0))
|
|
success = CHATFalse;
|
|
|
|
// Call the callback?
|
|
/////////////////////
|
|
if(!success)
|
|
{
|
|
if(callback)
|
|
{
|
|
ciCallbackChangeNickParams params;
|
|
params.success = success;
|
|
params.oldNick = connection->nick;
|
|
params.newNick = (char *)newNick;
|
|
ID = ciGetNextID(chat);
|
|
ciAddCallback(chat, CALLBACK_CHANGE_NICK, (void*)callback, ¶ms, param, ID, NULL);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Send the request.
|
|
////////////////////
|
|
ciSocketSendf(&connection->chatSocket, "NICK :%s", newNick);
|
|
|
|
ID = ciAddNICKFilter(chat, connection->nick, newNick, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatChangeNickW(CHAT chat,
|
|
const unsigned short * newNick,
|
|
chatChangeNickCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* newNick_A = (char*)UCS2ToUTF8StringAlloc(newNick);
|
|
chatChangeNickA(chat, newNick_A, callback, param, blocking);
|
|
gsifree(newNick_A);
|
|
}
|
|
#endif
|
|
|
|
const char * chatGetNickA(CHAT chat)
|
|
{
|
|
CONNECTION;
|
|
|
|
if(!connection->connected)
|
|
return "";
|
|
|
|
return connection->nick;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * chatGetNickW(CHAT chat)
|
|
{
|
|
CONNECTION;
|
|
|
|
if(!connection->connected)
|
|
return L"";
|
|
|
|
return connection->nickW;
|
|
}
|
|
#endif
|
|
|
|
void chatFixNickA(char * newNick,
|
|
const char * oldNick)
|
|
{
|
|
int c;
|
|
char oldNickCopy[MAX_CHAT_NICK];
|
|
char *pOldNick = oldNickCopy;
|
|
assert(oldNick);
|
|
assert(newNick);
|
|
strzcpy(oldNickCopy, oldNick, MAX_CHAT_NICK);
|
|
//if(isdigit(*oldNick) || (*oldNick == '-'))
|
|
// 10-14-2004 Changed by Saad Nader
|
|
// Using the nickname rules for unique nicks
|
|
// commented out the previous rules
|
|
////////////////////////////////////////////////
|
|
if(*pOldNick == '@' || *pOldNick== '#' || *pOldNick== '+' || *pOldNick == ':')
|
|
*newNick++ = '_';
|
|
|
|
while((c = *pOldNick++) != '\0')
|
|
{
|
|
if(!strchr(VALID_NICK_CHARS, c))
|
|
c = '_';
|
|
|
|
*newNick++ = (char)c;
|
|
}
|
|
*newNick = '\0';
|
|
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatFixNickW(unsigned short* newNick,
|
|
const unsigned short* oldNick)
|
|
{
|
|
char* oldNick_A = (char*)UCS2ToUTF8StringAlloc(newNick);
|
|
char newNick_A[MAX_NICK];
|
|
|
|
chatFixNickA(newNick_A, oldNick_A);
|
|
|
|
UTF8ToUCS2String(newNick_A, newNick);
|
|
|
|
gsifree(oldNick_A);
|
|
|
|
GSI_UNUSED(oldNick);
|
|
}
|
|
#endif
|
|
|
|
const char * chatTranslateNickA(char * nick,
|
|
const char * extension)
|
|
{
|
|
int nickLen;
|
|
int extensionLen;
|
|
|
|
assert(nick);
|
|
assert(extension);
|
|
|
|
nickLen = (int)strlen(nick);
|
|
extensionLen = (int)strlen(extension);
|
|
|
|
if((extensionLen < nickLen) && (strcasecmp(nick + nickLen - extensionLen, extension) == 0))
|
|
{
|
|
nick[nickLen - extensionLen] = '\0';
|
|
return nick;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
const unsigned short * chatTranslateNickW(unsigned short * nick,
|
|
const unsigned short * extension)
|
|
{
|
|
char nick_A[MAX_NICK];
|
|
char extension_A[MAX_NICK];
|
|
const char * translatedNick_A;
|
|
|
|
assert(nick);
|
|
assert(extension);
|
|
|
|
UCS2ToAsciiString(nick, nick_A);
|
|
UCS2ToAsciiString(extension, extension_A);
|
|
|
|
translatedNick_A = chatTranslateNickA(nick_A, extension_A);
|
|
|
|
if(translatedNick_A)
|
|
{
|
|
AsciiToUCS2String(translatedNick_A, nick);
|
|
return nick;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
int chatGetUserID(CHAT chat)
|
|
{
|
|
CONNECTION;
|
|
|
|
return connection->userID;
|
|
}
|
|
|
|
int chatGetProfileID(CHAT chat)
|
|
{
|
|
CONNECTION;
|
|
|
|
return connection->profileID;
|
|
}
|
|
|
|
static void ciSetQuietModeEnumJoinedChannelsA(CHAT chat,
|
|
int index,
|
|
const char * channel,
|
|
void * param)
|
|
{
|
|
// Setup a filter.
|
|
//////////////////
|
|
ciAddUNQUIETFilter(chat, channel);
|
|
|
|
GSI_UNUSED(index);
|
|
GSI_UNUSED(param);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
static void ciSetQuietModeEnumJoinedChannelsW(CHAT chat,
|
|
int index,
|
|
const unsigned short * channel,
|
|
void * param)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
ciSetQuietModeEnumJoinedChannelsA(chat, index, channel_A, param);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetQuietMode(CHAT chat,
|
|
CHATBool quiet)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
// Check if its the current mode.
|
|
/////////////////////////////////
|
|
if(connection->quiet == quiet)
|
|
return;
|
|
|
|
// Send the message.
|
|
////////////////////
|
|
if(quiet)
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s +q", connection->nick);
|
|
else
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s -q", connection->nick);
|
|
|
|
// Set the mode.
|
|
////////////////
|
|
connection->quiet = quiet;
|
|
|
|
// Are we disabling it?
|
|
///////////////////////
|
|
if(!quiet)
|
|
{
|
|
// Clear all the player lists.
|
|
//////////////////////////////
|
|
ciClearAllUsers(chat);
|
|
|
|
// Setup a filter for each joined channel.
|
|
//////////////////////////////////////////
|
|
#ifdef GSI_UNICODE
|
|
ciEnumJoinedChannels(chat, ciSetQuietModeEnumJoinedChannelsW, NULL);
|
|
#else
|
|
ciEnumJoinedChannels(chat, ciSetQuietModeEnumJoinedChannelsA, NULL);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void chatAuthenticateCDKeyA(CHAT chat,
|
|
const char * cdkey,
|
|
chatAuthenticateCDKeyCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CHATBool success = CHATTrue;
|
|
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
assert(cdkey);
|
|
assert(cdkey[0]);
|
|
assert(callback);
|
|
assert(connection->connected);
|
|
|
|
// Check we're connected.
|
|
/////////////////////////
|
|
if(!connection->connected)
|
|
return;
|
|
|
|
// No key.
|
|
//////////
|
|
if(!cdkey || !cdkey[0])
|
|
success = CHATFalse;
|
|
|
|
// Call the callback?
|
|
/////////////////////
|
|
if(!success)
|
|
{
|
|
if(callback)
|
|
{
|
|
ciCallbackAuthenticateCDKeyParams params;
|
|
params.result = 0;
|
|
params.message = "";
|
|
ID = ciGetNextID(chat);
|
|
ciAddCallback(chat, CALLBACK_AUTHENTICATE_CDKEY, (void*)callback, ¶ms, param, ID, NULL);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Send the request.
|
|
////////////////////
|
|
ciSocketSendf(&connection->chatSocket, "CDKEY %s", cdkey);
|
|
|
|
ID = ciAddCDKEYFilter(chat, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatAuthenticateCDKeyW(CHAT chat,
|
|
const unsigned short* cdkey,
|
|
chatAuthenticateCDKeyCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* cdkey_A = (char*)UCS2ToUTF8StringAlloc(cdkey);
|
|
chatAuthenticateCDKeyA(chat, cdkey_A, callback, param, blocking);
|
|
gsifree(cdkey_A);
|
|
}
|
|
#endif
|
|
|
|
/*************
|
|
** CHANNELS **
|
|
*************/
|
|
void chatEnumChannelsA(CHAT chat,
|
|
const char * filter,
|
|
chatEnumChannelsCallbackEach callbackEach,
|
|
chatEnumChannelsCallbackAll callbackAll,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
assert((callbackAll != NULL) || (callbackEach != NULL));
|
|
|
|
if(!filter)
|
|
filter = "";
|
|
|
|
ciSocketSendf(&connection->chatSocket, "LIST %s", filter);
|
|
|
|
ID = ciAddLISTFilter(chat, callbackEach, callbackAll, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatEnumChannelsW(CHAT chat,
|
|
const unsigned short * filter,
|
|
chatEnumChannelsCallbackEach callbackEach,
|
|
chatEnumChannelsCallbackAll callbackAll,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* filter_A = (char*)UCS2ToUTF8StringAlloc(filter);
|
|
chatEnumChannelsA(chat, filter_A, callbackEach, callbackAll, param, blocking);
|
|
gsifree(filter_A);
|
|
}
|
|
#endif
|
|
|
|
void chatEnterChannelA(CHAT chat,
|
|
const char * channel,
|
|
const char * password,
|
|
chatChannelCallbacks * callbacks,
|
|
chatEnterChannelCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callbacks != NULL);
|
|
|
|
if(password == NULL)
|
|
password = "";
|
|
|
|
ciSocketSendf(&connection->chatSocket, "JOIN %s %s", channel, password);
|
|
|
|
ID = ciAddJOINFilter(chat, channel, callback, param, callbacks, password);
|
|
|
|
// Entering.
|
|
////////////
|
|
ciChannelEntering(chat, channel);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatEnterChannelW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * password,
|
|
chatChannelCallbacks * callbacks,
|
|
chatEnterChannelCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* password_A = (char*)UCS2ToUTF8StringAlloc(password);
|
|
chatEnterChannelA(chat, channel_A, password_A, callbacks, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
gsifree(password_A);
|
|
}
|
|
#endif
|
|
|
|
void chatLeaveChannelA(CHAT chat,
|
|
const char * channel,
|
|
const char * reason)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
|
|
if(!reason)
|
|
reason = "";
|
|
|
|
ciSocketSendf(&connection->chatSocket, "PART %s :%s", channel, reason);
|
|
|
|
// Left the channel.
|
|
////////////////////
|
|
ciChannelLeft(chat, channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatLeaveChannelW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short* reason)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* reason_A = (char*)UCS2ToUTF8StringAlloc(reason);
|
|
chatLeaveChannelA(chat, channel_A, reason_A);
|
|
gsifree(channel_A);
|
|
gsifree(reason_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSendChannelMessageA(CHAT chat,
|
|
const char * channel,
|
|
const char * message,
|
|
int type)
|
|
{
|
|
chatChannelCallbacks * callbacks;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_TYPE(type);
|
|
|
|
if (!message || !message[0])
|
|
return;
|
|
if(type == CHAT_MESSAGE)
|
|
ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :%s", channel, message);
|
|
else if(type == CHAT_ACTION)
|
|
ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :\001ACTION %s\001", channel, message);
|
|
else if(type == CHAT_NOTICE)
|
|
ciSocketSendf(&connection->chatSocket, "NOTICE %s :%s", channel, message);
|
|
else if(type == CHAT_UTM)
|
|
ciSocketSendf(&connection->chatSocket, "UTM %s :%s", channel, message);
|
|
else if(type == CHAT_ATM)
|
|
ciSocketSendf(&connection->chatSocket, "ATM %s :%s", channel, message);
|
|
else
|
|
return;
|
|
|
|
// We don't get these back, so call the callbacks.
|
|
//////////////////////////////////////////////////
|
|
callbacks = ciGetChannelCallbacks(chat, channel);
|
|
if(callbacks != NULL)
|
|
{
|
|
ciCallbackChannelMessageParams params;
|
|
params.channel = (char *)channel;
|
|
params.user = connection->nick;
|
|
params.message = (char *)message;
|
|
params.type = type;
|
|
ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, channel);
|
|
}
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSendChannelMessageW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * message,
|
|
int type)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* message_A = (char*)UCS2ToUTF8StringAlloc(message);
|
|
chatSendChannelMessageA(chat, channel_A, message_A, type);
|
|
gsifree(channel_A);
|
|
gsifree(message_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetChannelTopicA(CHAT chat,
|
|
const char * channel,
|
|
const char * topic)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
|
|
if(topic == NULL)
|
|
topic = "";
|
|
|
|
ciSocketSendf(&connection->chatSocket, "TOPIC %s :%s", channel, topic);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetChannelTopicW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * topic)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* topic_A = (char*)UCS2ToUTF8StringAlloc(topic);
|
|
chatSetChannelTopicA(chat, channel_A, topic_A);
|
|
gsifree(channel_A);
|
|
gsifree(topic_A);
|
|
}
|
|
#endif
|
|
|
|
void chatGetChannelTopicA(CHAT chat,
|
|
const char * channel,
|
|
chatGetChannelTopicCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
const char * topic;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
// Check if we already have the topic.
|
|
//////////////////////////////////////
|
|
topic = ciGetChannelTopic(chat, channel);
|
|
if(topic)
|
|
{
|
|
ciCallbackGetChannelTopicParams params;
|
|
|
|
ID = ciGetNextID(chat);
|
|
|
|
params.success = CHATTrue;
|
|
params.channel = (char *)channel;
|
|
params.topic = (char *)topic;
|
|
ciAddCallback(chat, CALLBACK_GET_CHANNEL_TOPIC, (void*)callback, ¶ms, param, ID, channel);
|
|
}
|
|
else
|
|
{
|
|
ciSocketSendf(&connection->chatSocket, "TOPIC %s", channel);
|
|
|
|
ID = ciAddTOPICFilter(chat, channel, callback, param);
|
|
}
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetChannelTopicW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatGetChannelTopicCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatGetChannelTopicA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetChannelModeA(CHAT chat,
|
|
const char * channel,
|
|
CHATChannelMode * mode)
|
|
{
|
|
char buffer[64];
|
|
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(mode != NULL);
|
|
|
|
// Build the mode string.
|
|
/////////////////////////
|
|
strcpy(buffer, "XiXpXsXmXnXtXlXe");
|
|
if(mode->InviteOnly)
|
|
buffer[0] = '+';
|
|
else
|
|
buffer[0] = '-';
|
|
if(mode->Private)
|
|
buffer[2] = '+';
|
|
else
|
|
buffer[2] = '-';
|
|
if(mode->Secret)
|
|
buffer[4] = '+';
|
|
else
|
|
buffer[4] = '-';
|
|
if(mode->Moderated)
|
|
buffer[6] = '+';
|
|
else
|
|
buffer[6] = '-';
|
|
if(mode->NoExternalMessages)
|
|
buffer[8] = '+';
|
|
else
|
|
buffer[8] = '-';
|
|
if(mode->OnlyOpsChangeTopic)
|
|
buffer[10] = '+';
|
|
else
|
|
buffer[10] = '-';
|
|
if(mode->Limit > 0)
|
|
buffer[12] = '+';
|
|
else
|
|
buffer[12] = '-';
|
|
if(mode->OpsObeyChannelLimit)
|
|
buffer[14] = '+';
|
|
else
|
|
buffer[14] = '-';
|
|
|
|
// Add limit if needed.
|
|
///////////////////////
|
|
if(mode->Limit > 0)
|
|
sprintf(&buffer[strlen(buffer)], " %d", mode->Limit);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s %s", channel, buffer);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetChannelModeW(CHAT chat,
|
|
const unsigned short * channel,
|
|
CHATChannelMode * mode)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatSetChannelModeA(chat, channel_A, mode);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatGetChannelModeA(CHAT chat,
|
|
const char * channel,
|
|
chatGetChannelModeCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
// Are we in this channel?
|
|
//////////////////////////
|
|
if(ciInChannel(chat, channel))
|
|
{
|
|
CHATChannelMode mode;
|
|
|
|
// Get the mode locally.
|
|
////////////////////////
|
|
if(ciGetChannelMode(chat, channel, &mode))
|
|
{
|
|
ciCallbackGetChannelModeParams params;
|
|
|
|
// Get an ID.
|
|
/////////////
|
|
ID = ciGetNextID(chat);
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
params.success = CHATTrue;
|
|
params.channel = (char *)channel;
|
|
params.mode = &mode;
|
|
ciAddCallback(chat, CALLBACK_GET_CHANNEL_MODE, (void*)callback, ¶ms, param, ID, NULL);
|
|
|
|
CI_DO_BLOCKING;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s", channel);
|
|
|
|
ID = ciAddCMODEFilter(chat, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetChannelModeW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatGetChannelModeCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatGetChannelModeA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetChannelPasswordA(CHAT chat,
|
|
const char * channel,
|
|
CHATBool enable,
|
|
const char * password)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_PASSWORD();
|
|
|
|
if(enable)
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s +k %s", channel, password);
|
|
else
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s -k %s", channel, password);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetChannelPasswordW(CHAT chat,
|
|
const unsigned short * channel,
|
|
CHATBool enable,
|
|
const unsigned short * password)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* password_A = (char*)UCS2ToUTF8StringAlloc(password);
|
|
chatSetChannelPasswordA(chat, channel_A, enable, password_A);
|
|
gsifree(channel_A);
|
|
gsifree(password_A);
|
|
}
|
|
#endif
|
|
|
|
void chatGetChannelPasswordA(CHAT chat,
|
|
const char * channel,
|
|
chatGetChannelPasswordCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
ciCallbackGetChannelPasswordParams params;
|
|
const char * password;
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
// Check that we're in the channel.
|
|
///////////////////////////////////
|
|
if(!ciInChannel(chat, channel))
|
|
return; //ERRCON
|
|
|
|
// Get the password.
|
|
////////////////////
|
|
password = ciGetChannelPassword(chat, channel);
|
|
assert(password != NULL);
|
|
|
|
// Get an ID.
|
|
/////////////
|
|
ID = ciGetNextID(chat);
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
params.success = CHATTrue;
|
|
params.channel = (char *)channel;
|
|
params.enabled = CHATTrue;
|
|
params.password = (char *)password;
|
|
ciAddCallback(chat, CALLBACK_GET_CHANNEL_PASSWORD, (void*)callback, ¶ms, param, ID, NULL);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetChannelPasswordW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatGetChannelPasswordCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatGetChannelPasswordA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetChannelLimitA(CHAT chat,
|
|
const char * channel,
|
|
int limit)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(limit >= 0);
|
|
|
|
if(limit)
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s +l %d", channel, limit);
|
|
else
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s -l", channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetChannelLimitW(CHAT chat,
|
|
const unsigned short * channel,
|
|
int limit)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatSetChannelLimitA(chat, channel_A, limit);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatEnumChannelBansA(CHAT chat,
|
|
const char * channel,
|
|
chatEnumChannelBansCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s +b", channel);
|
|
|
|
ID = ciAddGETBANFilter(chat, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatEnumChannelBansW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatEnumChannelBansCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatEnumChannelBansA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatAddChannelBanA(CHAT chat,
|
|
const char * channel,
|
|
const char * ban)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_BAN();
|
|
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s +b %s", channel, ban);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatAddChannelBanW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * ban)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* ban_A = (char*)UCS2ToUTF8StringAlloc(ban);
|
|
chatAddChannelBanA(chat, channel_A, ban_A);
|
|
gsifree(channel_A);
|
|
gsifree(ban_A);
|
|
}
|
|
#endif
|
|
|
|
void chatRemoveChannelBanA(CHAT chat,
|
|
const char * channel,
|
|
const char * ban)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_BAN();
|
|
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s -b %s", channel, ban);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatRemoveChannelBanW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * ban)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* ban_A = (char*)UCS2ToUTF8StringAlloc(ban);
|
|
chatRemoveChannelBanA(chat, channel_A, ban_A);
|
|
gsifree(channel_A);
|
|
gsifree(ban_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetChannelGroupA(CHAT chat,
|
|
const char * channel,
|
|
const char * group)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
|
|
// No way to clear the group.
|
|
/////////////////////////////
|
|
if(!group || !group[0])
|
|
return;
|
|
|
|
ciSocketSendf(&connection->chatSocket, "SETGROUP %s %s", channel, group);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetChannelGroupW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short* group)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* group_A = (char*)UCS2ToUTF8StringAlloc(group);
|
|
chatSetChannelGroupA(chat, channel_A, group_A);
|
|
gsifree(channel_A);
|
|
gsifree(group_A);
|
|
}
|
|
#endif
|
|
|
|
int chatGetChannelNumUsersA(CHAT chat,
|
|
const char * channel)
|
|
{
|
|
CONNECTION;
|
|
if(!connection->connected)
|
|
return -1;
|
|
|
|
ASSERT_CHANNEL();
|
|
|
|
if(!channel || !channel[0])
|
|
return -1;
|
|
|
|
if(!ciInChannel(chat, channel))
|
|
return -1;
|
|
|
|
return ciGetChannelNumUsers(chat, channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
int chatGetChannelNumUsersW(CHAT chat,
|
|
const unsigned short * channel)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
int result = chatGetChannelNumUsersA(chat, channel_A);
|
|
gsifree(channel_A);
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
CHATBool chatInChannelA(CHAT chat,
|
|
const char * channel)
|
|
|
|
{
|
|
CONNECTION;
|
|
if(!connection->connected)
|
|
return CHATFalse;
|
|
|
|
ASSERT_CHANNEL();
|
|
|
|
if(!channel || !channel[0])
|
|
return CHATFalse;
|
|
|
|
return ciInChannel(chat, channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHATBool chatInChannelW(CHAT chat,
|
|
const unsigned short * channel)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
CHATBool result = chatInChannelA(chat, channel_A);
|
|
gsifree(channel_A);
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
|
|
/**********
|
|
** USERS **
|
|
**********/
|
|
static void ciEnumUsersCallback(CHAT chat, const char * channel, int numUsers, const char ** users, int * modes, void * param)
|
|
{
|
|
ciEnumUsersData * data;
|
|
CONNECTION;
|
|
|
|
// Check the args.
|
|
//////////////////
|
|
ASSERT_CHANNEL();
|
|
assert(numUsers >= 0);
|
|
#ifdef _DEBUG
|
|
{
|
|
int i;
|
|
if(numUsers > 0)
|
|
{
|
|
assert(users != NULL);
|
|
assert(modes != NULL);
|
|
}
|
|
for(i = 0 ; i < numUsers ; i++)
|
|
{
|
|
ASSERT_USER(users[i]);
|
|
ASSERT_TYPE(modes[i]);
|
|
}
|
|
}
|
|
#endif
|
|
assert(param != NULL);
|
|
|
|
// Get the data.
|
|
////////////////
|
|
data = (ciEnumUsersData *)param;
|
|
assert(data->callback != NULL);
|
|
|
|
// Call the callback directly.
|
|
//////////////////////////////
|
|
#ifdef GSI_UNICODE
|
|
{
|
|
unsigned short* channel_W = UTF8ToUCS2StringAlloc(channel);
|
|
unsigned short** users_W = UTF8ToUCS2StringArrayAlloc(users, numUsers);
|
|
data->callback(chat, CHATTrue, channel_W, numUsers, (const unsigned short**)users_W, modes, data->param);
|
|
gsifree(channel_W);
|
|
while(numUsers-- > 0)
|
|
gsifree(users_W[numUsers]);
|
|
gsifree(users_W);
|
|
}
|
|
#else
|
|
data->callback(chat, CHATTrue, channel, numUsers, users, modes, data->param);
|
|
#endif
|
|
}
|
|
|
|
void chatEnumUsersA(CHAT chat,
|
|
const char * channel,
|
|
chatEnumUsersCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
ciEnumUsersData data;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
//ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
if(channel == NULL)
|
|
channel = "";
|
|
|
|
// Is there a channel specified?
|
|
////////////////////////////////
|
|
if(channel[0] != '\0')
|
|
{
|
|
// Check if we have this one locally.
|
|
/////////////////////////////////////
|
|
if(ciInChannel(chat, channel))
|
|
{
|
|
// Get the users in the channel.
|
|
////////////////////////////////
|
|
data.callback = callback;
|
|
data.param = param;
|
|
ciChannelListUsers(chat, channel, ciEnumUsersCallback, &data);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
ciSocketSendf(&connection->chatSocket, "NAMES %s", channel);
|
|
|
|
// Channel needs to be empty, not NULL, for the filter.
|
|
///////////////////////////////////////////////////////
|
|
if(!channel[0])
|
|
channel = NULL;
|
|
|
|
ID = ciAddNAMESFilter(chat, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatEnumUsersW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatEnumUsersCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatEnumUsersA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
|
|
// Enumerates the channels that we are joined to
|
|
//////////////////////////////////////////////////////
|
|
void chatEnumJoinedChannels(CHAT chat,
|
|
chatEnumJoinedChannelsCallback callback,
|
|
void * param)
|
|
{
|
|
ciEnumJoinedChannels(chat, callback, param);
|
|
}
|
|
|
|
void chatSendUserMessageA(CHAT chat,
|
|
const char * user,
|
|
const char * message,
|
|
int type)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_USER(user);
|
|
ASSERT_TYPE(type);
|
|
|
|
if (!message || message[0] == 0)
|
|
return;
|
|
|
|
if(type == CHAT_MESSAGE)
|
|
ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :%s", user, message);
|
|
else if(type == CHAT_ACTION)
|
|
ciSocketSendf(&connection->chatSocket, "PRIVMSG %s :\001ACTION %s\001", user, message);
|
|
else if(type == CHAT_NOTICE)
|
|
ciSocketSendf(&connection->chatSocket, "NOTICE %s :%s", user, message);
|
|
else if(type == CHAT_UTM)
|
|
ciSocketSendf(&connection->chatSocket, "UTM %s :%s", user, message);
|
|
else if(type == CHAT_ATM)
|
|
ciSocketSendf(&connection->chatSocket, "ATM %s :%s", user, message);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSendUserMessageW(CHAT chat,
|
|
const unsigned short * user,
|
|
const unsigned short * message,
|
|
int type)
|
|
{
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
char* message_A = (char*)UCS2ToUTF8StringAlloc(message);
|
|
chatSendUserMessageA(chat, user_A, message_A, type);
|
|
gsifree(user_A);
|
|
gsifree(message_A);
|
|
}
|
|
#endif
|
|
|
|
void chatGetUserInfoA(CHAT chat,
|
|
const char * user,
|
|
chatGetUserInfoCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_USER(user);
|
|
assert(callback != NULL);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "WHOIS %s", user);
|
|
|
|
ID = ciAddWHOISFilter(chat, user, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetUserInfoW(CHAT chat,
|
|
const unsigned short * user,
|
|
chatGetUserInfoCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
chatGetUserInfoA(chat, user_A, callback, param, blocking);
|
|
gsifree(user_A);
|
|
}
|
|
#endif
|
|
|
|
void chatGetBasicUserInfoA(CHAT chat,
|
|
const char * nick,
|
|
chatGetBasicUserInfoCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
const char * user;
|
|
const char * address;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_USER(nick);
|
|
assert(callback != NULL);
|
|
|
|
// Check if we already have it.
|
|
///////////////////////////////
|
|
if(ciGetUserBasicInfoA(chat, nick, &user, &address))
|
|
{
|
|
ciCallbackGetBasicUserInfoParams params;
|
|
|
|
params.success = CHATTrue;
|
|
params.nick = (char *)nick;
|
|
params.user = (char *)user;
|
|
params.address = (char *)address;
|
|
|
|
ID = ciGetNextID(chat);
|
|
|
|
ciAddCallback(chat, CALLBACK_GET_BASIC_USER_INFO, (void*)callback, ¶ms, param, ID, NULL);
|
|
}
|
|
else
|
|
{
|
|
ciSocketSendf(&connection->chatSocket, "WHO %s", nick);
|
|
|
|
ID = ciAddWHOFilter(chat, nick, callback, param);
|
|
}
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetBasicUserInfoW(CHAT chat,
|
|
const unsigned short * nick,
|
|
chatGetBasicUserInfoCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* nick_A = (char*)UCS2ToUTF8StringAlloc(nick);
|
|
chatGetBasicUserInfoA(chat, nick_A, callback, param, blocking);
|
|
gsifree(nick_A);
|
|
}
|
|
#endif
|
|
|
|
CHATBool chatGetBasicUserInfoNoWaitA(CHAT chat,
|
|
const char * nick,
|
|
const char ** user,
|
|
const char ** address)
|
|
{
|
|
CONNECTION;
|
|
// 2002.Feb.28.JED - added additional check, was blowing up in GSA
|
|
if(!connection)
|
|
return CHATFalse;
|
|
if(!connection->connected)
|
|
return CHATFalse;
|
|
|
|
ASSERT_USER(nick);
|
|
|
|
return ciGetUserBasicInfoA(chat, nick, user, address);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHATBool chatGetBasicUserInfoNoWaitW(CHAT chat,
|
|
const unsigned short * nick,
|
|
const unsigned short ** user,
|
|
const unsigned short ** address)
|
|
{
|
|
char nick_A[MAX_NICK];
|
|
|
|
CONNECTION;
|
|
// 2002.Feb.28.JED - added additional check, was blowing up in GSA
|
|
if(!connection)
|
|
return CHATFalse;
|
|
if(!connection->connected)
|
|
return CHATFalse;
|
|
|
|
assert(nick);
|
|
|
|
UCS2ToAsciiString(nick, nick_A);
|
|
return ciGetUserBasicInfoW(chat, nick_A, user, address);
|
|
}
|
|
#endif
|
|
|
|
void chatGetChannelBasicUserInfoA(CHAT chat,
|
|
const char * channel,
|
|
chatGetChannelBasicUserInfoCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "WHO %s", channel);
|
|
|
|
ID = ciAddCWHOFilter(chat, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetChannelBasicUserInfoW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatGetChannelBasicUserInfoCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatGetChannelBasicUserInfoA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
void chatInviteUserA(CHAT chat,
|
|
const char * channel,
|
|
const char * user)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_USER(user);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "INVITE %s %s", user, channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatInviteUserW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
chatInviteUserA(chat, channel_A, user_A);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
}
|
|
#endif
|
|
|
|
void chatKickUserA(CHAT chat,
|
|
const char * channel,
|
|
const char * user,
|
|
const char * reason)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_USER(user);
|
|
|
|
if(reason == NULL)
|
|
reason = "";
|
|
|
|
ciSocketSendf(&connection->chatSocket, "KICK %s %s :%s", channel, user, reason);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatKickUserW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
const unsigned short * reason)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
char* reason_A = (char*)UCS2ToUTF8StringAlloc(reason);
|
|
chatKickUserA(chat, channel_A, user_A, reason_A);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
gsifree(reason_A);
|
|
}
|
|
#endif
|
|
|
|
void chatBanUserA(CHAT chat,
|
|
const char * channel,
|
|
const char * user)
|
|
{
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_USER(user);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "WHOIS %s", user);
|
|
|
|
ciAddBANFilter(chat, user, channel);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatBanUserW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
chatBanUserA(chat, channel_A, user_A);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetUserModeA(CHAT chat,
|
|
const char * channel,
|
|
const char * user,
|
|
int mode)
|
|
{
|
|
int sign;
|
|
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_USER(user);
|
|
ASSERT_TYPE(mode);
|
|
|
|
sign = (mode & CHAT_OP)?'+':'-';
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s %co %s", channel, sign, user);
|
|
|
|
sign = (mode & CHAT_VOICE)?'+':'-';
|
|
ciSocketSendf(&connection->chatSocket, "MODE %s %cv %s", channel, sign, user);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetUserModeW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
int mode)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
chatSetUserModeA(chat, channel_A, user_A, mode);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
}
|
|
#endif
|
|
|
|
void chatGetUserModeA(CHAT chat,
|
|
const char * channel,
|
|
const char * user,
|
|
chatGetUserModeCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
int mode;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_USER(user);
|
|
assert(callback != NULL);
|
|
|
|
// Get the mode.
|
|
////////////////
|
|
mode = ciGetUserMode(chat, channel, user);
|
|
if(mode != -1)
|
|
{
|
|
ciCallbackGetUserModeParams params;
|
|
params.success = CHATTrue;
|
|
params.channel = (char *)channel;
|
|
params.user = (char *)user;
|
|
params.mode = mode;
|
|
|
|
ID = ciGetNextID(chat);
|
|
ciAddCallback(chat, CALLBACK_GET_USER_MODE, (void*)callback, ¶ms, param, ID, NULL);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
|
|
ciSocketSendf(&connection->chatSocket, "WHO %s", user);
|
|
|
|
ID = ciAddUMODEFilter(chat, user, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetUserModeW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
chatGetUserModeCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
chatGetUserModeA(chat, channel_A, user_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
}
|
|
#endif
|
|
|
|
CHATBool chatGetUserModeNoWaitA(CHAT chat,
|
|
const char * channel,
|
|
const char * user,
|
|
int * mode)
|
|
{
|
|
CONNECTION;
|
|
if(!connection->connected)
|
|
return CHATFalse;
|
|
|
|
ASSERT_CHANNEL();
|
|
ASSERT_USER(user);
|
|
assert(mode);
|
|
|
|
// Get the mode.
|
|
////////////////
|
|
*mode = ciGetUserMode(chat, channel, user);
|
|
|
|
return (CHATBool)(*mode != -1);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
CHATBool chatGetUserModeNoWaitW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
int * mode)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
char* user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
CHATBool result = chatGetUserModeNoWaitA(chat, channel_A, user_A, mode);
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
|
|
void chatGetUdpRelayA(CHAT chat,
|
|
const char * channel,
|
|
chatGetUdpRelayCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
ASSERT_CHANNEL();
|
|
assert(callback != NULL);
|
|
|
|
ciSocketSendf(&connection->chatSocket, "GETUDPRELAY %s", channel);
|
|
|
|
ID = ciAddGETUDPRELAYFilter(chat, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
|
|
#ifdef GSI_UNICODE
|
|
void chatGetUdpRelayW(CHAT chat,
|
|
const unsigned short * channel,
|
|
chatGetUdpRelayCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
chatGetUdpRelayA(chat, channel_A, callback, param, blocking);
|
|
gsifree(channel_A);
|
|
}
|
|
#endif
|
|
|
|
/*********
|
|
** KEYS **
|
|
*********/
|
|
void chatSetGlobalKeysA(CHAT chat,
|
|
int num,
|
|
const char ** keys,
|
|
const char ** values)
|
|
{
|
|
char buffer[512];
|
|
const char * key;
|
|
const char * value;
|
|
int i;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
if(!keys || !values)
|
|
return;
|
|
|
|
strcpy(buffer, "SETKEY :");
|
|
for(i = 0 ; i < num ; i++)
|
|
{
|
|
key = keys[i];
|
|
if(!key || !key[0])
|
|
return;
|
|
value = values[i];
|
|
if(!value)
|
|
value = "";
|
|
sprintf(buffer + strlen(buffer), "\\%s\\%s", key, value);
|
|
}
|
|
|
|
ciSocketSend(&connection->chatSocket, buffer);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetGlobalKeysW(CHAT chat,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
const unsigned short ** values)
|
|
{
|
|
char** keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
char** values_A = (char**)UCS2ToUTF8StringArrayAlloc(values, num);
|
|
int i = 0;
|
|
chatSetGlobalKeysA(chat, num, (const char**)keys_A, (const char**)values_A);
|
|
for (; i < num; i++)
|
|
{
|
|
gsifree(keys_A[i]);
|
|
gsifree(values_A[i]);
|
|
}
|
|
gsifree(keys_A);
|
|
gsifree(values_A);
|
|
}
|
|
#endif
|
|
|
|
static char * ciRandomCookie()
|
|
{
|
|
static char cookie[4];
|
|
static int nextCookie = 0;
|
|
|
|
sprintf(cookie, "%03d", nextCookie++);
|
|
nextCookie %= 1000;
|
|
|
|
return cookie;
|
|
}
|
|
|
|
static void ciSendGetKey(CHAT chat,
|
|
const char * target,
|
|
const char * cookie,
|
|
int num,
|
|
const char ** keys)
|
|
{
|
|
char buffer[512];
|
|
int len;
|
|
int i;
|
|
int j;
|
|
int keyLen;
|
|
|
|
CONNECTION;
|
|
|
|
assert(target && target[0]);
|
|
assert(cookie && cookie[0]);
|
|
assert(num >= 1);
|
|
assert(keys);
|
|
|
|
// Start off the buffer.
|
|
////////////////////////
|
|
sprintf(buffer, "GETKEY %s %s 0 :", target, cookie);
|
|
len = (int)strlen(buffer);
|
|
|
|
// Add the keys.
|
|
////////////////
|
|
for(i = 0 ; i < num ; i++)
|
|
{
|
|
// Check for a blank.
|
|
/////////////////////
|
|
if(!keys[i] || !keys[i][0])
|
|
continue;
|
|
|
|
// Check lengths.
|
|
/////////////////
|
|
keyLen = (int)strlen(keys[i]);
|
|
if((len + keyLen + 1) >= (int)sizeof(buffer))
|
|
return;
|
|
|
|
// Add the key.
|
|
///////////////
|
|
buffer[len++] = '\\';
|
|
memcpy(buffer + len, keys[i], (unsigned int)keyLen);
|
|
for(j = len ; j < (len + keyLen) ; j++)
|
|
if(buffer[j] == '\\')
|
|
buffer[j] = '/';
|
|
len += keyLen;
|
|
buffer[len] = '\0';
|
|
}
|
|
|
|
// Send it.
|
|
///////////
|
|
ciSocketSend(&connection->chatSocket, buffer);
|
|
}
|
|
|
|
void chatGetGlobalKeysA(CHAT chat,
|
|
const char * target,
|
|
int num,
|
|
const char ** keys,
|
|
chatGetGlobalKeysCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char * cookie;
|
|
const char * channel;
|
|
int ID;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
assert(num >= 0);
|
|
assert(keys);
|
|
|
|
if(!target || !target[0])
|
|
target = connection->nick;
|
|
|
|
// Get a cookie.
|
|
////////////////
|
|
cookie = ciRandomCookie();
|
|
|
|
// Send the request.
|
|
////////////////////
|
|
ciSendGetKey(chat, target, cookie, num, keys);
|
|
|
|
// Check if this is a channel or a user.
|
|
////////////////////////////////////////
|
|
if(target[0] == '#')
|
|
channel = target;
|
|
else
|
|
channel = NULL;
|
|
|
|
ID = ciAddGETKEYFilter(chat, cookie, num, keys, channel, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetGlobalKeysW(CHAT chat,
|
|
const unsigned short * target,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
chatGetGlobalKeysCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* target_A;
|
|
char** keys_A;
|
|
int i = 0;
|
|
|
|
assert(target);
|
|
assert(keys);
|
|
|
|
target_A = (char*)UCS2ToUTF8StringAlloc(target);
|
|
keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
|
|
chatGetGlobalKeysA(chat, target_A, num, (const char**)keys_A, callback, param, blocking);
|
|
gsifree(target_A);
|
|
|
|
for (; i < num; i++)
|
|
gsifree(keys_A[i]);
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
void chatSetChannelKeysA(CHAT chat,
|
|
const char * channel,
|
|
const char * user,
|
|
int num,
|
|
const char ** keys,
|
|
const char ** values)
|
|
{
|
|
char buffer[512];
|
|
const char * value;
|
|
int i;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
if(!user || !user[0])
|
|
sprintf(buffer, "SETCHANKEY %s :", channel);
|
|
else
|
|
sprintf(buffer, "SETCKEY %s %s :", channel, user);
|
|
for(i = 0 ; i < num ; i++)
|
|
{
|
|
value = values[i];
|
|
if(!value)
|
|
value = "";
|
|
sprintf(buffer + strlen(buffer), "\\%s\\%s", keys[i], value);
|
|
}
|
|
|
|
ciSocketSend(&connection->chatSocket, buffer);
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatSetChannelKeysW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
const unsigned short ** values)
|
|
{
|
|
char* channel_A;
|
|
char* user_A;
|
|
char** keys_A;
|
|
char** values_A;
|
|
int i = 0;
|
|
|
|
channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
values_A = (char**)UCS2ToUTF8StringArrayAlloc(values, num);
|
|
|
|
chatSetChannelKeysA(chat, channel_A, user_A, num, (const char**)keys_A, (const char**)values_A);
|
|
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
|
|
for (; i < num; i++)
|
|
{
|
|
gsifree(keys_A[i]);
|
|
gsifree(values_A[i]);
|
|
}
|
|
|
|
gsifree(keys_A);
|
|
gsifree(values_A);
|
|
}
|
|
#endif
|
|
|
|
static CHATBool ciSendGetChannelKey(CHAT chat,
|
|
const char * channel,
|
|
const char * nick,
|
|
const char * cookie,
|
|
int num,
|
|
const char ** keys)
|
|
{
|
|
char buffer[512];
|
|
int len;
|
|
int i;
|
|
int j;
|
|
int keyLen;
|
|
CHATBool getBrocastKeys = CHATFalse;
|
|
|
|
CONNECTION;
|
|
|
|
assert(channel && channel[0]);
|
|
assert(cookie && cookie[0]);
|
|
assert(!num || keys);
|
|
|
|
// Start off the buffer.
|
|
////////////////////////
|
|
if(!nick || !nick[0])
|
|
sprintf(buffer, "GETCHANKEY %s %s 0 :", channel, cookie);
|
|
else
|
|
sprintf(buffer, "GETCKEY %s %s %s 0 :", channel, nick, cookie);
|
|
len = (int)strlen(buffer);
|
|
|
|
// Add the keys.
|
|
////////////////
|
|
for(i = 0 ; i < num ; i++)
|
|
{
|
|
// Check for a blank.
|
|
/////////////////////
|
|
if(!keys[i] || !keys[i][0])
|
|
continue;
|
|
|
|
// Check for b_*.
|
|
/////////////////
|
|
if(strcmp(keys[i], "b_*") == 0)
|
|
{
|
|
getBrocastKeys = CHATTrue;
|
|
continue;
|
|
}
|
|
|
|
// Check lengths.
|
|
/////////////////
|
|
keyLen = (int)strlen(keys[i]);
|
|
if((len + keyLen + 1) >= (int)sizeof(buffer))
|
|
continue;
|
|
|
|
// Add the key.
|
|
///////////////
|
|
buffer[len++] = '\\';
|
|
memcpy(buffer + len, keys[i], (unsigned int)keyLen);
|
|
for(j = len ; j < (len + keyLen) ; j++)
|
|
if(buffer[j] == '\\')
|
|
buffer[j] = '/';
|
|
len += keyLen;
|
|
buffer[len] = '\0';
|
|
}
|
|
|
|
// Check for broadcast keys.
|
|
////////////////////////////
|
|
if(getBrocastKeys)
|
|
{
|
|
if((len + 4) < (int)sizeof(buffer))
|
|
{
|
|
strcpy(buffer + len, "\\b_*");
|
|
len += 4;
|
|
}
|
|
}
|
|
|
|
// Check for requesting all keys on a room.
|
|
///////////////////////////////////////////
|
|
if(!num && (!nick || !nick[0]))
|
|
{
|
|
strcpy(buffer + len, "*");
|
|
len++;
|
|
}
|
|
|
|
// Send it.
|
|
///////////
|
|
ciSocketSend(&connection->chatSocket, buffer);
|
|
|
|
return getBrocastKeys;
|
|
}
|
|
|
|
void chatGetChannelKeysA(CHAT chat,
|
|
const char * channel,
|
|
const char * user,
|
|
int num,
|
|
const char ** keys,
|
|
chatGetChannelKeysCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char * cookie;
|
|
int ID;
|
|
CHATBool getBroadcastKeys;
|
|
CONNECTION;
|
|
CONNECTED;
|
|
|
|
assert(num >= 0);
|
|
assert(!num || keys);
|
|
|
|
// Get a cookie.
|
|
////////////////
|
|
cookie = ciRandomCookie();
|
|
|
|
// Send the request.
|
|
////////////////////
|
|
getBroadcastKeys = ciSendGetChannelKey(chat, channel, user, cookie, num, keys);
|
|
|
|
if(!user || !user[0])
|
|
ID = ciAddGETCHANKEYFilter(chat, cookie, num, keys, getBroadcastKeys, callback, param);
|
|
else
|
|
ID = ciAddGETCKEYFilter(chat, cookie, num, keys, (CHATBool)(strcmp(user, "*") == 0), getBroadcastKeys, callback, param);
|
|
|
|
CI_DO_BLOCKING;
|
|
}
|
|
#ifdef GSI_UNICODE
|
|
void chatGetChannelKeysW(CHAT chat,
|
|
const unsigned short * channel,
|
|
const unsigned short * user,
|
|
int num,
|
|
const unsigned short ** keys,
|
|
chatGetChannelKeysCallback callback,
|
|
void * param,
|
|
CHATBool blocking)
|
|
{
|
|
char* channel_A;
|
|
char* user_A;
|
|
char** keys_A;
|
|
int i = 0;
|
|
|
|
channel_A = (char*)UCS2ToUTF8StringAlloc(channel);
|
|
user_A = (char*)UCS2ToUTF8StringAlloc(user);
|
|
keys_A = (char**)UCS2ToUTF8StringArrayAlloc(keys, num);
|
|
|
|
chatGetChannelKeysA(chat, channel_A, user_A, num, (const char**)keys_A, callback, param, blocking);
|
|
|
|
gsifree(channel_A);
|
|
gsifree(user_A);
|
|
|
|
for (; i < num; i++)
|
|
gsifree(keys_A[i]);
|
|
|
|
gsifree(keys_A);
|
|
}
|
|
#endif
|
|
|
|
// Check if a given nickname is valid. Looks for illegal IRC characters.
|
|
// [in] nick - The nickname to validate
|
|
int ciNickIsValid(const char* nick)
|
|
{
|
|
if (strlen(nick) >= MAX_CHAT_NICK)
|
|
return CHAT_NICK_TOO_LONG;
|
|
|
|
// Empty nick is invalid
|
|
if ((NULL == nick) || ('\0' == *nick))
|
|
return CHAT_INVALID;
|
|
|
|
|
|
// 10-14-2004 Changed by Saad Nader
|
|
// Using the nickname rules for unique nicks
|
|
// commented out the previous rules
|
|
////////////////////////////////////////////////
|
|
// Nick can't start with a number or a '+', '@', '#'
|
|
//if(isdigit(*oldNick) || (*oldNick == '-'))
|
|
|
|
if(*nick == '@' || *nick == '#' || *nick == '+' || *nick == ':')
|
|
return CHAT_INVALID;
|
|
|
|
// Make sure each character is valid
|
|
while(*nick != '\0')
|
|
{
|
|
// If the character isn't in the valid set, the nick is not valid
|
|
if (NULL == strchr(VALID_NICK_CHARS,*nick++))
|
|
return CHAT_INVALID;
|
|
}
|
|
|
|
return CHAT_NICK_OK;
|
|
}
|
|
|
|
/****************
|
|
** NICK ERRORS **
|
|
****************/
|
|
void ciNickError(CHAT chat, int type, const char * nick, int numSuggestedNicks, char ** suggestedNicks)
|
|
{
|
|
CONNECTION;
|
|
|
|
// Check if there's a nick-in-use callback.
|
|
///////////////////////////////////////////
|
|
if(connection->nickErrorCallback)
|
|
{
|
|
ciCallbackNickErrorParams params;
|
|
|
|
// Add the callback.
|
|
////////////////////
|
|
memset(¶ms, 0, sizeof(ciCallbackNickErrorParams));
|
|
params.type = type;
|
|
params.nick = (char *)nick;
|
|
params.numSuggestedNicks = numSuggestedNicks;
|
|
params.suggestedNicks = suggestedNicks;
|
|
ciAddCallback(chat, CALLBACK_NICK_ERROR, (void*)connection->nickErrorCallback, ¶ms, connection->connectParam, 0, NULL);
|
|
}
|
|
else
|
|
{
|
|
// There's no callback, disconnect.
|
|
///////////////////////////////////
|
|
connection->connecting = CHATFalse;
|
|
|
|
// Call the callback.
|
|
/////////////////////
|
|
if(connection->connectCallback != NULL)
|
|
connection->connectCallback(chat, CHATFalse, CHAT_NICK_ERROR, connection->connectParam);
|
|
}
|
|
}
|
|
|