/* GameSpy Chat SDK Dan "Mr. Pants" Schoenblum dan@gamespy.com Copyright 1999-2007 GameSpy Industries, Inc devsupport@gamespy.com */ /************* ** INCLUDES ** *************/ #include #include #include #include #include "chatMain.h" #include "chatSocket.h" #include "chatHandlers.h" #include "chatChannel.h" #include "chatCallbacks.h" #include "chatCrypt.h" #if defined(_WIN32) // Silence the cast function* to void* warning. // Since we are explicitly casting it, I'm not sure why the compiler warns #pragma warning(disable:4054) // Silence the "conditional expression is constant" on our "while(1)" statements #pragma warning(disable:4127) #endif /************ ** DEFINES ** ************/ #define FILTER_TIMEOUT 60000 #define NAMES_ARRAY_INC 100 #define ASSERT_TYPE(type) assert((type >= 0) && (type < NUM_TYPES)); #define ASSERT_STR(str) assert(str != NULL); assert(str[0] != '\0'); #define RPL_WELCOME "001" #define RPL_USRIP "302" #define RPL_WHOISUSER "311" #define RPL_ENDOFWHO "315" #define RPL_ENDOFWHOIS "318" #define RPL_WHOISCHANNELS "319" #define RPL_LISTSTART "321" #define RPL_LIST "322" #define RPL_LISTEND "323" #define RPL_CHANNELMODEIS "324" #define RPL_NOTOPIC "331" #define RPL_TOPIC "332" #define RPL_WHOREPLY "352" #define RPL_NAMEREPLY "353" #define RPL_ENDOFNAMES "366" #define RPL_BANLIST "367" #define RPL_ENDOFBANLIST "368" #define RPL_GETKEY "700" #define RPL_ENDGETKEY "701" #define RPL_GETCKEY "702" #define RPL_ENDGETCKEY "703" #define RPL_GETCHANKEY "704" #define RPL_SECUREKEY "705" #define RPL_CDKEY "706" #define RPL_LOGIN "707" #define RPL_GETUDPRELAY "712" #define ERR_NOSUCHNICK "401" #define ERR_NOSUCHCHANNEL "403" #define ERR_TOOMANYCHANNELS "405" #define ERR_ERRONEUSNICKNAME "432" #define ERR_NICKNAMEINUSE "433" #define ERR_CHANNELISFULL "471" #define ERR_INVITEONLYCHAN "473" #define ERR_BANNEDFROMCHAN "474" #define ERR_BADCHANNELKEY "475" #define ERR_BADCHANMASK "476" #define ERR_LOGIN_FAILED "708" #define ERR_NO_UNIQUE_NICK "709" #define ERR_UNIQUE_NICK_EXPIRED "710" #define ERR_REGISTER_NICK_FAILED "711" #define MODE_END 0 #define MODE_BAN 1 #define MODE_INVITE_ONLY 2 #define MODE_LIMIT 3 #define MODE_PRIVATE 4 #define MODE_SECRET 5 #define MODE_KEY 6 #define MODE_MODERATED 7 #define MODE_NO_EXTERNAL_MESSAGES 8 #define MODE_ONLY_OPS_CHANGE_TOPIC 9 #define MODE_OP 10 #define MODE_VOICE 11 #define MODE_USERS_HIDDEN 12 #define MODE_RECEIVE_WALLOPS 13 #define MODE_OPS_OBEY_CHANNEL_LIMIT 14 #define FINISH_FILTER ciFinishFilter(chat, filter, ¶ms) #define IS_ALPHA(c) ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) enum { TYPE_LIST, TYPE_JOIN, TYPE_TOPIC, TYPE_NAMES, TYPE_WHOIS, TYPE_CMODE, TYPE_UMODE, TYPE_BAN, TYPE_GETBAN, TYPE_NICK, TYPE_WHO, TYPE_CWHO, TYPE_GETKEY, TYPE_GETCKEY, TYPE_GETCHANKEY, TYPE_UNQUIET, TYPE_CDKEY, TYPE_GETUDPRELAY, NUM_TYPES }; /********** ** TYPES ** **********/ typedef struct ciModeChange { int mode; CHATBool enable; char * param; } ciModeChange; typedef struct ciFilterMatch { int type; const char * name; const char * name2; } ciFilterMatch; typedef struct LISTData { CHATBool gotStart; int numChannels; char ** channels; int * numUsers; char ** topics; } LISTData; typedef struct JOINData { chatChannelCallbacks callbacks; CHATBool joined; char password[MAX_PASSWORD]; } JOINData; typedef struct NAMESData { int len; int numUsers; char ** users; int * modes; } NAMESData; typedef struct WHOISData { char * user; char * name; char * address; int numChannels; char ** channels; } WHOISData; typedef struct BANData { char * channel; } BANData; typedef struct GETBANData { int numBans; char ** bans; } GETBANData; typedef struct GETKEYData { int num; char ** keys; char * channel; } GETKEYData; typedef struct GETCKEYData { int num; char ** keys; CHATBool channel; CHATBool allBroadcastKeys; } GETCKEYData; typedef struct GETCHANKEYData { int num; char ** keys; CHATBool allBroadcastKeys; } GETCHANKEYData; /***************** ** HANDLER DECS ** *****************/ void ciPrivmsgHandler(CHAT chat, const ciServerMessage * message); void ciNoticeHandler(CHAT chat, const ciServerMessage * message); void ciUTMHandler(CHAT chat, const ciServerMessage * message); void ciATMHandler(CHAT chat, const ciServerMessage * message); void ciPingHandler(CHAT chat, const ciServerMessage * message); void ciNickHandler(CHAT chat, const ciServerMessage * message); void ciJoinHandler(CHAT chat, const ciServerMessage * message); void ciPartHandler(CHAT chat, const ciServerMessage * message); void ciKickHandler(CHAT chat, const ciServerMessage * message); void ciQuitHandler(CHAT chat, const ciServerMessage * message); void ciKillHandler(CHAT chat, const ciServerMessage * message); void ciTopicHandler(CHAT chat, const ciServerMessage * message); void ciModeHandler(CHAT chat, const ciServerMessage * message); void ciErrorHandler(CHAT chat, const ciServerMessage * message); void ciNameReplyHandler(CHAT chat, const ciServerMessage * message); void ciEndOfNamesHandler(CHAT chat, const ciServerMessage * message); void ciInviteHandler(CHAT chat, const ciServerMessage * message); void ciRplTopicHandler(CHAT chat, const ciServerMessage * message); void ciRplNoTopicHandler(CHAT chat, const ciServerMessage * message); void ciErrNickInUseHandler(CHAT chat, const ciServerMessage * message); void ciRplWhoReplyHandler(CHAT chat, const ciServerMessage * message); void ciRplUserIPHandler(CHAT chat, const ciServerMessage * message); void ciRplListStartHandler(CHAT chat, const ciServerMessage * message); void ciRplListHandler(CHAT chat, const ciServerMessage * message); void ciRplListEndHandler(CHAT chat, const ciServerMessage * message); void ciRplChannelModeIsHandler(CHAT chat, const ciServerMessage * message); void ciRplWhoisUserHandler(CHAT chat, const ciServerMessage * message); void ciRplWhoisChannelsHandler(CHAT chat, const ciServerMessage * message); void ciRplEndOfWhoisHandler(CHAT chat, const ciServerMessage * message); void ciRplBanListHandler(CHAT chat, const ciServerMessage * message); void ciRplEndOfBanListHandler(CHAT chat, const ciServerMessage * message); void ciRplWelcomeHandler(CHAT chat, const ciServerMessage * message); void ciRplEndOfWhoHandler(CHAT chat, const ciServerMessage * message); void ciRplGetKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplEndGetKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplGetCKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplEndGetCKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplGetChanKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplSecureKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplCDKeyHandler(CHAT chat, const ciServerMessage * message); void ciRplLoginHandler(CHAT chat, const ciServerMessage * message); void ciRplGetUdpRelayHandler(CHAT chat, const ciServerMessage * message); void ciErrNoSuchChannelHandler(CHAT chat, const ciServerMessage * message); void ciErrTooManyChannelsHandler(CHAT chat, const ciServerMessage * message); void ciErrChannelIsFullHandler(CHAT chat, const ciServerMessage * message); void ciErrInviteOnlyChanHandler(CHAT chat, const ciServerMessage * message); void ciErrBannedFromChanHandler(CHAT chat, const ciServerMessage * message); void ciErrBadChannelKeyHandler(CHAT chat, const ciServerMessage * message); void ciErrBadChanMaskHandler(CHAT chat, const ciServerMessage * message); void ciErrNoSuchNickHandler(CHAT chat, const ciServerMessage * message); void ciErrErroneusNicknameHandler(CHAT chat, const ciServerMessage * message); void ciErrLoginFailedHandler(CHAT chat, const ciServerMessage * message); void ciErrNoUniqueNickHandler(CHAT chat, const ciServerMessage * message); void ciErrUniqueNickExpiredHandler(CHAT chat, const ciServerMessage * message); void ciErrRegisterNickFailedHandler(CHAT chat, const ciServerMessage * message); /************ ** GLOBALS ** ************/ ciServerMessageType serverMessageTypes[] = { { "PRIVMSG", ciPrivmsgHandler }, { "NOTICE", ciNoticeHandler }, { "UTM", ciUTMHandler }, { "ATM", ciATMHandler }, { "PING", ciPingHandler }, { "NICK", ciNickHandler }, { "JOIN", ciJoinHandler }, { "PART", ciPartHandler }, { "KICK", ciKickHandler }, { "QUIT", ciQuitHandler }, { "KILL", ciKillHandler }, { "TOPIC", ciTopicHandler }, { "MODE", ciModeHandler }, { "ERROR", ciErrorHandler }, { "INVITE", ciInviteHandler }, { RPL_NAMEREPLY, ciNameReplyHandler }, { RPL_ENDOFNAMES, ciEndOfNamesHandler }, { RPL_TOPIC, ciRplTopicHandler }, { RPL_NOTOPIC, ciRplNoTopicHandler }, { RPL_WHOREPLY, ciRplWhoReplyHandler }, { RPL_USRIP, ciRplUserIPHandler }, { RPL_LISTSTART, ciRplListStartHandler }, { RPL_LIST, ciRplListHandler }, { RPL_LISTEND, ciRplListEndHandler }, { RPL_CHANNELMODEIS, ciRplChannelModeIsHandler }, { RPL_WHOISUSER, ciRplWhoisUserHandler }, { RPL_WHOISCHANNELS, ciRplWhoisChannelsHandler }, { RPL_ENDOFWHOIS, ciRplEndOfWhoisHandler }, { RPL_BANLIST, ciRplBanListHandler }, { RPL_ENDOFBANLIST, ciRplEndOfBanListHandler }, { RPL_WELCOME, ciRplWelcomeHandler }, { RPL_ENDOFWHO, ciRplEndOfWhoHandler }, { RPL_GETKEY, ciRplGetKeyHandler }, { RPL_ENDGETKEY, ciRplEndGetKeyHandler }, { RPL_GETCKEY, ciRplGetCKeyHandler }, { RPL_ENDGETCKEY, ciRplEndGetCKeyHandler }, { RPL_GETCHANKEY, ciRplGetChanKeyHandler }, { RPL_SECUREKEY, ciRplSecureKeyHandler }, { RPL_CDKEY, ciRplCDKeyHandler }, { RPL_LOGIN, ciRplLoginHandler }, { RPL_GETUDPRELAY, ciRplGetUdpRelayHandler }, { ERR_NICKNAMEINUSE, ciErrNickInUseHandler }, { ERR_NOSUCHCHANNEL, ciErrNoSuchChannelHandler }, { ERR_TOOMANYCHANNELS, ciErrTooManyChannelsHandler }, { ERR_CHANNELISFULL, ciErrChannelIsFullHandler }, { ERR_INVITEONLYCHAN, ciErrInviteOnlyChanHandler }, { ERR_BANNEDFROMCHAN, ciErrBannedFromChanHandler }, { ERR_BADCHANNELKEY, ciErrBadChannelKeyHandler }, { ERR_BADCHANMASK, ciErrBadChanMaskHandler }, { ERR_NOSUCHNICK, ciErrNoSuchNickHandler }, { ERR_ERRONEUSNICKNAME, ciErrErroneusNicknameHandler }, { ERR_LOGIN_FAILED, ciErrLoginFailedHandler }, { ERR_NO_UNIQUE_NICK, ciErrNoUniqueNickHandler }, { ERR_UNIQUE_NICK_EXPIRED, ciErrUniqueNickExpiredHandler }, { ERR_REGISTER_NICK_FAILED, ciErrRegisterNickFailedHandler } }; int numServerMessageTypes = (sizeof(serverMessageTypes) / sizeof(ciServerMessageType)); /************** ** FUNCTIONS ** **************/ static ciServerMessageFilter * ciFindFilter(CHAT chat, int numMatches, ciFilterMatch * matches) { int i; const char * name; const char * name2; ciServerMessageFilter * filter; CONNECTION; assert(numMatches > 0); assert(matches); for(filter = connection->filterList ; filter != NULL ; filter = filter->pnext) { for(i = 0 ; i < numMatches ; i++) { ASSERT_TYPE(matches[i].type); if(filter->type == matches[i].type) { name = matches[i].name; name2 = matches[i].name2; if((!name && !filter->name) || (name && filter->name && (strcasecmp(name, filter->name) == 0))) { if((!name2 && !filter->name2) || (name2 && filter->name2 && (strcasecmp(name2, filter->name2) == 0))) { // Someone's interested in this filter, so extend the timeout. ////////////////////////////////////////////////////////////// filter->timeout = (current_time() + FILTER_TIMEOUT); return filter; } } } } } return NULL; } static ciServerMessageFilter * ciFindGetKeyFilter(CHAT chat, const char * channel) { GETKEYData * data; ciServerMessageFilter * filter; CONNECTION; assert(channel); assert(channel[0]); for(filter = connection->filterList ; filter != NULL ; filter = filter->pnext) { if(filter->type == TYPE_GETKEY) { data = (GETKEYData *)filter->data; if(strcasecmp(data->channel, channel) == 0) return filter; } } return NULL; } static void ciDestroyFilter(ciServerMessageFilter * filter) { assert(filter != NULL); gsifree(filter->data); gsifree(filter->name); gsifree(filter->name2); gsifree(filter); } static void ciRemoveFilter(CHAT chat, ciServerMessageFilter * filter) { ciServerMessageFilter * pcurr; ciServerMessageFilter * pprev = NULL; CONNECTION; assert(filter != NULL); for(pcurr = connection->filterList ; pcurr != NULL ; pcurr = pcurr->pnext) { if(pcurr == filter) { if(connection->filterList == pcurr) connection->filterList = pcurr->pnext; if(connection->lastFilter == pcurr) connection->lastFilter = pprev; if(pprev != NULL) pprev->pnext = pcurr->pnext; ciDestroyFilter(pcurr); return; } pprev = pcurr; } //ERRCON } // Calls the callback, if not NULL, then removes the filter. //////////////////////////////////////////////////////////// static void ciFinishFilter(CHAT chat, ciServerMessageFilter * filter, void * params) { int i; assert(filter); ASSERT_TYPE(filter->type); // Check the type. ////////////////// if(filter->type == TYPE_LIST) { LISTData * data = (LISTData *)filter->data; if(filter->callback2) ciAddCallback_(chat, CALLBACK_ENUM_CHANNELS_ALL, filter->callback2, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnumChannelsAllParams)); for(i = 0 ; i < data->numChannels ; i++) { gsifree(data->channels[i]); gsifree(data->topics[i]); } gsifree(data->channels); gsifree(data->topics); gsifree(data->numUsers); } else if(filter->type == TYPE_JOIN) { if(filter->callback != NULL) ciAddCallback_(chat, CALLBACK_ENTER_CHANNEL, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnterChannelParams)); } else if(filter->type == TYPE_TOPIC) { const char * channel = ((ciCallbackGetChannelTopicParams *)params)->channel; if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_CHANNEL_TOPIC, filter->callback, params, filter->param, filter->ID, channel, sizeof(ciCallbackGetChannelTopicParams)); } else if(filter->type == TYPE_NAMES) { NAMESData * data = (NAMESData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_ENUM_USERS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnumUsersParams)); for(i = 0 ; i < data->numUsers ; i++) gsifree(data->users[i]); gsifree(data->users); gsifree(data->modes); } else if(filter->type == TYPE_WHOIS) { WHOISData * data = (WHOISData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_USER_INFO, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetUserInfoParams)); for(i = 0 ; i < data->numChannels ; i++) gsifree(data->channels[i]); gsifree(data->channels); gsifree(data->name); gsifree(data->address); gsifree(data->user); } else if(filter->type == TYPE_WHO) { if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_BASIC_USER_INFO, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetBasicUserInfoParams)); } else if(filter->type == TYPE_CWHO) { if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_CHANNEL_BASIC_USER_INFO, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetBasicUserInfoParams)); } else if(filter->type == TYPE_CMODE) { if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_CHANNEL_MODE, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetChannelModeParams)); } else if(filter->type == TYPE_UMODE) { if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_USER_MODE, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetUserModeParams)); } else if(filter->type == TYPE_GETUDPRELAY) { if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_UDPRELAY, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetUdpRelayParams)); } else if(filter->type == TYPE_BAN) { BANData * data = (BANData *)filter->data; gsifree(data->channel); } else if(filter->type == TYPE_GETBAN) { GETBANData * data = (GETBANData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_ENUM_CHANNEL_BANS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackEnumChannelBansParams)); // gsifree the filter. /////////////////// for(i = 0 ; i < data->numBans ; i++) gsifree(data->bans[i]); } else if(filter->type == TYPE_NICK) { if(filter->callback) ciAddCallback_(chat, CALLBACK_CHANGE_NICK, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackChangeNickParams)); } else if(filter->type == TYPE_GETKEY) { GETKEYData * data = (GETKEYData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_GLOBAL_KEYS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetGlobalKeysParams)); gsifree(data->channel); for(i = 0 ; i < data->num ; i++) gsifree(data->keys[i]); gsifree(data->keys); } else if(filter->type == TYPE_GETCKEY) { GETCKEYData * data = (GETCKEYData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_CHANNEL_KEYS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetChannelKeysParams)); for(i = 0 ; i < data->num ; i++) gsifree(data->keys[i]); gsifree(data->keys); } else if(filter->type == TYPE_GETCHANKEY) { GETCHANKEYData * data = (GETCHANKEYData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_GET_CHANNEL_KEYS, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackGetChannelKeysParams)); for(i = 0 ; i < data->num ; i++) gsifree(data->keys[i]); gsifree(data->keys); } else if(filter->type == TYPE_UNQUIET) { NAMESData * data = (NAMESData *)filter->data; if(filter->callback) ciAddCallback_(chat, CALLBACK_NEW_USER_LIST, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackNewUserListParams)); for(i = 0 ; i < data->numUsers ; i++) gsifree(data->users[i]); gsifree(data->users); gsifree(data->modes); } else if(filter->type == TYPE_CDKEY) { if(filter->callback) ciAddCallback_(chat, CALLBACK_AUTHENTICATE_CDKEY, filter->callback, params, filter->param, filter->ID, NULL, sizeof(ciCallbackAuthenticateCDKeyParams)); } else { assert(0); } // Remove the filter. ///////////////////// ciRemoveFilter(chat, filter); } // Called when a filter times out to deal with calling the failed callback. /////////////////////////////////////////////////////////////////////////// static void ciFilterTimedout(CHAT chat, ciServerMessageFilter * filter) { assert(filter); ASSERT_TYPE(filter->type); // Check the type. ////////////////// if(filter->type == TYPE_LIST) { ciCallbackEnumChannelsAllParams params; params.success = CHATFalse; params.numChannels = 0; params.channels = NULL; params.topics = NULL; params.numUsers = NULL; FINISH_FILTER; } else if(filter->type == TYPE_JOIN) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATEnterTimedOut; params.channel = filter->name; FINISH_FILTER; } else if(filter->type == TYPE_TOPIC) { ciCallbackGetChannelTopicParams params; params.success = CHATFalse; params.channel = filter->name; params.topic = NULL; FINISH_FILTER; } else if(filter->type == TYPE_NAMES) { ciCallbackEnumUsersParams params; params.success = CHATFalse; params.channel = filter->name; params.numUsers = 0; params.users = NULL; params.modes = NULL; FINISH_FILTER; } else if(filter->type == TYPE_WHOIS) { ciCallbackGetUserInfoParams params; params.success = CHATFalse; params.nick = filter->name; params.user = NULL; params.name = NULL; params.address = NULL; params.numChannels = 0; params.channels = NULL; FINISH_FILTER; } else if(filter->type == TYPE_WHO) { ciCallbackGetBasicUserInfoParams params; params.success = CHATFalse; params.nick = filter->name; params.user = NULL; params.address = NULL; FINISH_FILTER; } else if(filter->type == TYPE_CWHO) { ciCallbackGetChannelBasicUserInfoParams params; params.success = CHATFalse; params.channel = filter->name; params.nick = NULL; params.user = NULL; params.address = NULL; FINISH_FILTER; } else if(filter->type == TYPE_CMODE) { ciCallbackGetChannelModeParams params; params.success = CHATFalse; params.channel = filter->name; params.mode = NULL; FINISH_FILTER; } else if(filter->type == TYPE_UMODE) { ciCallbackGetUserModeParams params; params.success = CHATFalse; params.channel = filter->name2; params.user = filter->name; params.mode = 0; FINISH_FILTER; } else if(filter->type == TYPE_BAN) { ciFinishFilter(chat, filter, NULL); } else if(filter->type == TYPE_GETBAN) { ciCallbackEnumChannelBansParams params; params.channel = filter->name; params.numBans = 0; params.bans = NULL; FINISH_FILTER; } else if(filter->type == TYPE_NICK) { ciCallbackChangeNickParams params; params.success = CHATFalse; params.oldNick = filter->name; params.newNick = filter->name2; FINISH_FILTER; } else if(filter->type == TYPE_GETKEY) { ciCallbackGetGlobalKeysParams params; params.success = CHATFalse; params.user = NULL; params.num = 0; params.keys = NULL; params.values = NULL; FINISH_FILTER; } else if(filter->type == TYPE_GETCKEY) { ciCallbackGetChannelKeysParams params; params.success = CHATFalse; params.channel = NULL; params.user = NULL; params.num = 0; params.keys = NULL; params.values = NULL; FINISH_FILTER; } else if(filter->type == TYPE_GETCHANKEY) { ciCallbackGetChannelKeysParams params; params.success = CHATFalse; params.channel = NULL; params.user = NULL; params.num = 0; params.keys = NULL; params.values = NULL; FINISH_FILTER; } else if(filter->type == TYPE_UNQUIET) { ciRemoveFilter(chat, filter); } else if(filter->type == TYPE_CDKEY) { ciCallbackAuthenticateCDKeyParams params; params.result = 0; params.message = "Timed out"; FINISH_FILTER; } else if(filter->type == TYPE_GETUDPRELAY) { ciCallbackGetUdpRelayParams params; params.channel = filter->name; params.udpIp = NULL; params.udpKey = 0; params.udpPort = 0; FINISH_FILTER; } else { assert(0); } } void ciFilterThink(CHAT chat) { ciServerMessageFilter * filter; ciServerMessageFilter * pnext; gsi_time now; CONNECTION; now = 0; now = 2; now = current_time(); for(filter = connection->filterList ; filter != NULL ; filter = pnext) { pnext = filter->pnext; if(now > filter->timeout) { ciFilterTimedout(chat, filter); } } } int ciGetNextID(CHAT chat) { int rcode; CONNECTION; // Store the next. ////////////////// rcode = connection->nextID; // Increment the ID. //////////////////// if(connection->nextID == INT_MAX) connection->nextID = 1; else connection->nextID++; return rcode; } CHATBool ciCheckFiltersForID(CHAT chat, int ID) { ciServerMessageFilter * filter; CONNECTION; assert(ID > 0); for(filter = connection->filterList ; filter != NULL ; filter = filter->pnext) { // Check for a matching ID. /////////////////////////// if(filter->ID == ID) return CHATTrue; } // No matches. ////////////// return CHATFalse; } void ciCleanupFilters(CHAT chat) { CONNECTION; while(connection->filterList) ciFilterTimedout(chat, connection->filterList); // PANTS|03.13.01 - changed from ciRemoveFilter } static int ciAddFilter(CHAT chat, int type, const char * name, const char * name2, void * callback, void * callback2, void * param, void * data) { ciServerMessageFilter * filter; CONNECTION; // Create the filter. ///////////////////// filter = (ciServerMessageFilter *)gsimalloc(sizeof(ciServerMessageFilter)); if(filter == NULL) return 0; //ERRCON // Setup the filter. //////////////////// memset(filter, 0, sizeof(ciServerMessageFilter)); filter->type = type; filter->timeout = (current_time() + FILTER_TIMEOUT); filter->callback = callback; filter->callback2 = callback2; filter->param = param; filter->data = data; if(name) filter->name = goastrdup(name); else filter->name = NULL; if(name2) filter->name2 = goastrdup(name2); else filter->name2 = NULL; filter->ID = ciGetNextID(chat); // Add the filter to the end of the list. ///////////////////////////////////////// if(connection->filterList == NULL) connection->filterList = filter; else connection->lastFilter->pnext = filter; connection->lastFilter = filter; return filter->ID; } int ciAddLISTFilter(CHAT chat, chatEnumChannelsCallbackEach callbackEach, chatEnumChannelsCallbackAll callbackAll, void * param) { LISTData * data = (LISTData *)gsimalloc(sizeof(LISTData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(LISTData)); return ciAddFilter(chat, TYPE_LIST, NULL, NULL, (void*)callbackEach, (void*)callbackAll, param, data); } int ciAddJOINFilter(CHAT chat, const char * channel, chatEnterChannelCallback callback, void * param, chatChannelCallbacks * callbacks, const char * password) { int rcode; JOINData * data; assert(password != NULL); assert(strlen(password) < MAX_PASSWORD); data = (JOINData *)gsimalloc(sizeof(JOINData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(JOINData)); data->callbacks = *callbacks; strzcpy(data->password, password, MAX_PASSWORD); rcode = ciAddFilter(chat, TYPE_JOIN, channel, NULL, (void*)callback, NULL, param, data); if(rcode == 0) gsifree(data); return rcode; } int ciAddTOPICFilter(CHAT chat, const char * channel, chatGetChannelTopicCallback callback, void * param) { return ciAddFilter(chat, TYPE_TOPIC, channel, NULL, (void*)callback, NULL, param, NULL); } int ciAddNAMESFilter(CHAT chat, const char * channel, chatEnumUsersCallback callback, void * param) { NAMESData * data = (NAMESData *)gsimalloc(sizeof(NAMESData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(NAMESData)); return ciAddFilter(chat, TYPE_NAMES, channel, NULL, (void*)callback, NULL, param, data); } int ciAddWHOISFilter(CHAT chat, const char * user, chatGetUserInfoCallback callback, void * param) { int rcode; WHOISData * data = (WHOISData *)gsimalloc(sizeof(WHOISData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(WHOISData)); rcode = ciAddFilter(chat, TYPE_WHOIS, user, NULL, (void*)callback, NULL, param, data); if(rcode == 0) gsifree(data); return rcode; } int ciAddWHOFilter(CHAT chat, const char * user, chatGetBasicUserInfoCallback callback, void * param) { return ciAddFilter(chat, TYPE_WHO, user, NULL, (void*)callback, NULL, param, NULL); } int ciAddCWHOFilter(CHAT chat, const char * channel, chatGetChannelBasicUserInfoCallback callback, void * param) { return ciAddFilter(chat, TYPE_CWHO, channel, NULL, (void*)callback, NULL, param, NULL); } int ciAddCMODEFilter(CHAT chat, const char * channel, chatGetChannelModeCallback callback, void * param) { return ciAddFilter(chat, TYPE_CMODE, channel, NULL, (void*)callback, NULL, param, NULL); } int ciAddUMODEFilter(CHAT chat, const char * user, const char * channel, chatGetUserModeCallback callback, void * param) { return ciAddFilter(chat, TYPE_UMODE, user, channel, (void*)callback, NULL, param, NULL); } int ciAddGETUDPRELAYFilter(CHAT chat, const char * channel, chatGetUdpRelayCallback callback, void * param) { return ciAddFilter(chat, TYPE_GETUDPRELAY, channel, NULL, (void*)callback, NULL, param, NULL); } int ciAddBANFilter(CHAT chat, const char * user, const char * channel) { BANData * data = (BANData *)gsimalloc(sizeof(BANData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(BANData)); data->channel = goastrdup(channel); if(data->channel == NULL) { gsifree(data); return 0; //ERRCON } return ciAddFilter(chat, TYPE_BAN, user, NULL, NULL, NULL, NULL, data); } int ciAddGETBANFilter(CHAT chat, const char * channel, chatEnumChannelBansCallback callback, void * param) { GETBANData * data = (GETBANData *)gsimalloc(sizeof(GETBANData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(GETBANData)); return ciAddFilter(chat, TYPE_GETBAN, channel, NULL, (void*)callback, NULL, param, data); } int ciAddNICKFilter(CHAT chat, const char * oldNick, const char * newNick, chatChangeNickCallback callback, void * param) { return ciAddFilter(chat, TYPE_NICK, oldNick, newNick, (void*)callback, NULL, param, NULL); } int ciAddGETKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, const char * channel, chatGetGlobalKeysCallback callback, void * param) { int i; GETKEYData * data = (GETKEYData *)gsimalloc(sizeof(GETKEYData)); if(!data) return 0; memset(data, 0, sizeof(GETKEYData)); data->num = num; if(channel) { data->channel = goastrdup(channel); if(!data->channel) { gsifree(data); return 0; } } data->keys = (char **)gsimalloc(sizeof(char *) * num); if(!data->keys) { gsifree(data->channel); gsifree(data); return 0; } for(i = 0 ; i < num ; i++) { data->keys[i] = goastrdup(keys[i]); if(!data->keys[i]) { for( i-- ; i >= 0 ; i--) gsifree(data->keys[i]); gsifree(data->keys); gsifree(data->channel); gsifree(data); return 0; } } return ciAddFilter(chat, TYPE_GETKEY, cookie, NULL, (void*)callback, NULL, param, data); } int ciAddGETCKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, CHATBool channel, CHATBool getBroadcastKeys, chatGetChannelKeysCallback callback, void * param) { int src; int dest; GETCKEYData * data = (GETCKEYData *)gsimalloc(sizeof(GETCKEYData)); if(!data) return 0; memset(data, 0, sizeof(GETCKEYData)); data->allBroadcastKeys = getBroadcastKeys; data->num = num; data->channel = channel; if(getBroadcastKeys) data->num--; data->keys = (char **)gsimalloc(sizeof(char *) * data->num); if(!data->keys) { gsifree(data); return 0; } for(src = 0, dest = 0 ; src < num ; src++) { if(strcmp(keys[src], "b_*") != 0) { data->keys[dest] = goastrdup(keys[src]); if(!data->keys[dest]) { for( dest-- ; dest >= 0 ; dest--) gsifree(data->keys[dest]); gsifree(data->keys); gsifree(data); return 0; } dest++; } } data->num = dest; return ciAddFilter(chat, TYPE_GETCKEY, cookie, NULL, (void*)callback, NULL, param, data); } int ciAddGETCHANKEYFilter(CHAT chat, const char * cookie, int num, const char ** keys, CHATBool getBroadcastKeys, chatGetChannelKeysCallback callback, void * param) { int src; int dest; GETCHANKEYData * data = (GETCHANKEYData *)gsimalloc(sizeof(GETCHANKEYData)); if(!data) return 0; memset(data, 0, sizeof(GETCHANKEYData)); data->allBroadcastKeys = getBroadcastKeys; data->num = num; if(getBroadcastKeys) data->num--; if(data->num) { data->keys = (char **)gsimalloc(sizeof(char *) * data->num); if(!data->keys) { gsifree(data); return 0; } for(src = 0, dest = 0 ; src < num ; src++) { if(strcmp(keys[src], "b_*") != 0) { data->keys[dest] = goastrdup(keys[src]); if(!data->keys[dest]) { for( dest-- ; dest >= 0 ; dest--) gsifree(data->keys[dest]); gsifree(data->keys); gsifree(data); return 0; } dest++; } } data->num = dest; } return ciAddFilter(chat, TYPE_GETCHANKEY, cookie, NULL, (void*)callback, NULL, param, data); } int ciAddUNQUIETFilter(CHAT chat, const char * channel) { chatChannelCallbacks * callbacks; NAMESData * data; callbacks = ciGetChannelCallbacks(chat, channel); if(!callbacks || !callbacks->newUserList) return 0; data = (NAMESData *)gsimalloc(sizeof(NAMESData)); if(data == NULL) return 0; //ERRCON memset(data, 0, sizeof(NAMESData)); return ciAddFilter(chat, TYPE_UNQUIET, channel, NULL, (void*)callbacks->newUserList, NULL, callbacks->param, data); } int ciAddCDKEYFilter(CHAT chat, chatAuthenticateCDKeyCallback callback, void * param) { return ciAddFilter(chat, TYPE_CDKEY, NULL, NULL, (void*)callback, NULL, param, NULL); } /***************** ** MODE PARSING ** *****************/ static ciModeChange * ciParseMode(char * mode, char ** params, int numParams) { CHATBool enable; int c; ciModeChange * changes = NULL; int numChanges = 0; ciModeChange * change; int modeChange; CHATBool addParam = CHATFalse; void * tempPtr; assert(mode != NULL); // Check the initial enable mode. ///////////////////////////////// if(*mode == '+') enable = CHATTrue; else if(*mode == '-') enable = CHATFalse; else return NULL; //ERRCON mode++; // Go through the mode string. ////////////////////////////// do { // Get the next character. ////////////////////////// c = *mode++; // Interpret the char. ////////////////////// switch(c) { case '+': enable = CHATTrue; modeChange = -1; break; case '-': enable = CHATFalse; modeChange = -1; break; case '\0': modeChange = MODE_END; addParam = CHATFalse; break; case 'i': modeChange = MODE_INVITE_ONLY; addParam = CHATFalse; break; case 'l': modeChange = MODE_LIMIT; addParam = CHATTrue; break; case 'p': modeChange = MODE_PRIVATE; addParam = CHATFalse; break; case 's': modeChange = MODE_SECRET; addParam = CHATFalse; break; case 'k': modeChange = MODE_KEY; addParam = CHATTrue; break; case 'm': modeChange = MODE_MODERATED; addParam = CHATFalse; break; case 'n': modeChange = MODE_NO_EXTERNAL_MESSAGES; addParam = CHATFalse; break; case 't': modeChange = MODE_ONLY_OPS_CHANGE_TOPIC; addParam = CHATFalse; break; case 'o': modeChange = MODE_OP; addParam = CHATTrue; break; case 'v': modeChange = MODE_VOICE; addParam = CHATTrue; break; case 'b': modeChange = MODE_BAN; addParam = CHATTrue; break; case 'u': modeChange = MODE_USERS_HIDDEN; addParam = CHATFalse; break; case 'w': modeChange = MODE_RECEIVE_WALLOPS; addParam = CHATFalse; break; case 'e': modeChange = MODE_OPS_OBEY_CHANNEL_LIMIT; addParam = CHATFalse; break; default: // Unknown mode. //////////////// //assert(0); modeChange = -1; } // Make the change. /////////////////// if(modeChange != -1) { tempPtr = gsirealloc(changes, sizeof(ciModeChange) * (numChanges + 1)); if(tempPtr == NULL) { gsifree(changes); return NULL; //ERRCON } changes = (ciModeChange *)tempPtr; change = &changes[numChanges++]; memset(change, 0, sizeof(ciModeChange)); change->enable = enable; change->mode = modeChange; // Add a param if needed. ///////////////////////// if(addParam) { // PANTS - 09.27.00 - changed to work even if no param if(numParams > 0) { change->param = *params++; numParams--; } else change->param = NULL; } } } while(c != '\0'); return changes; } static void ciApplyChangesToMode(CHATChannelMode * mode, ciModeChange * changes) { ciModeChange * change; // Go through all the changes. ////////////////////////////// for(change = changes ; change->mode != MODE_END ; change++) { switch(change->mode) { case MODE_BAN: break; case MODE_INVITE_ONLY: mode->InviteOnly = change->enable; break; case MODE_LIMIT: if(change->enable && change->param) mode->Limit = atoi(change->param); else mode->Limit = 0; break; case MODE_PRIVATE: mode->Private = change->enable; break; case MODE_SECRET: mode->Secret = change->enable; break; case MODE_KEY: break; case MODE_MODERATED: mode->Moderated = change->enable; break; case MODE_NO_EXTERNAL_MESSAGES: mode->NoExternalMessages = change->enable; break; case MODE_ONLY_OPS_CHANGE_TOPIC: mode->OnlyOpsChangeTopic = change->enable; break; case MODE_OP: break; case MODE_VOICE: break; case MODE_USERS_HIDDEN: break; case MODE_RECEIVE_WALLOPS: break; case MODE_OPS_OBEY_CHANNEL_LIMIT: mode->OpsObeyChannelLimit = change->enable; break; default: assert(0); } } } /************* ** HANDLERS ** *************/ void ciPrivmsgHandler(CHAT chat, const ciServerMessage * message) { char * ctcp; char * target; char * from; CHATBool action = CHATFalse; char * msg; int len; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciPrivmsgHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON target = message->params[0]; msg = message->params[1]; from = message->nick; // Check for CTCP. ////////////////// len = (int)strlen(msg); ctcp = ""; if((msg[0] == '\001') && IS_ALPHA(msg[1]) && (msg[len - 1] == '\001')) { char * str; // Strip the ending \001. // PANTS|08.14.00 ///////////////////////// msg[len - 1] = '\0'; // End the command. /////////////////// str = strchr(msg, ' '); if(str != NULL) { // The start of the CTCP command. ///////////////////////////////// ctcp = &msg[1]; // End the ctcp. //////////////// *str = '\0'; msg = (str + 1); } } // Is it an action? /////////////////// if(strcmp(ctcp, "ACTION") == 0) { // It's an action. ////////////////// action = CHATTrue; } #if 0 // Is it a ping? //////////////// else if(strcmp(ctcp, "PING") == 0) { // Send back a ping. //////////////////// ciSocketSendf(&connection->chatSocket, "NOTICE %s :\001PING %s\001", from, msg); return; } #endif else if(ctcp[0] != '\0') { // Unsupported action, ignore. ////////////////////////////// return; } // Is it a private message? /////////////////////////// if(strcasecmp(target, connection->nick) == 0) { if(connection->globalCallbacks.privateMessage != NULL) { ciCallbackPrivateMessageParams params; params.user = from; params.message = msg; if(action) params.type = CHAT_ACTION; else params.type = CHAT_MESSAGE; ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); } } else { // Get the channel callbacks. ///////////////////////////// chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); if((callbacks != NULL) && (callbacks->channelMessage != NULL)) { ciCallbackChannelMessageParams params; params.channel = target; params.user = from; params.message = msg; if(action) params.type = CHAT_ACTION; else params.type = CHAT_MESSAGE; ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); } } } void ciNoticeHandler(CHAT chat, const ciServerMessage * message) { char * target; char * msg; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciNoticeHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON target = message->params[0]; msg = message->params[1]; // Is it a private message? /////////////////////////// if(strcasecmp(target, connection->nick) == 0) { if(connection->globalCallbacks.privateMessage != NULL) { ciCallbackPrivateMessageParams params; if(message->nick != NULL) params.user = message->nick; else params.user = NULL; params.message = msg; params.type = CHAT_NOTICE; ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); } } else { // Get the channel callbacks. ///////////////////////////// chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); if((callbacks != NULL) && (callbacks->channelMessage != NULL)) { ciCallbackChannelMessageParams params; params.channel = target; if(message->nick != NULL) params.user = message->nick; else params.user = NULL; params.message = msg; params.type = CHAT_NOTICE; ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); } } } void ciUTMHandler(CHAT chat, const ciServerMessage * message) { char * target; char * msg; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciUTMHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON target = message->params[0]; msg = message->params[1]; // Is it a private message? /////////////////////////// if(strcasecmp(target, connection->nick) == 0) { if(connection->globalCallbacks.privateMessage != NULL) { ciCallbackPrivateMessageParams params; if(message->nick != NULL) params.user = message->nick; else params.user = NULL; params.message = msg; params.type = CHAT_UTM; ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); } } else { // Get the channel callbacks. ///////////////////////////// chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); if((callbacks != NULL) && (callbacks->channelMessage != NULL)) { ciCallbackChannelMessageParams params; params.channel = target; if(message->nick != NULL) params.user = message->nick; else params.user = NULL; params.message = msg; params.type = CHAT_UTM; ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); } } } void ciATMHandler(CHAT chat, const ciServerMessage * message) { char * target; char * msg; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciATMHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON target = message->params[0]; msg = message->params[1]; // Is it a private message? /////////////////////////// if(strcasecmp(target, connection->nick) == 0) { if(connection->globalCallbacks.privateMessage != NULL) { ciCallbackPrivateMessageParams params; if(message->nick != NULL) params.user = message->nick; else params.user = NULL; params.message = msg; params.type = CHAT_ATM; ciAddCallback(chat, CALLBACK_PRIVATE_MESSAGE, (void*)connection->globalCallbacks.privateMessage, ¶ms, connection->globalCallbacks.param, 0, NULL); } } else { // Get the channel callbacks. ///////////////////////////// chatChannelCallbacks * callbacks = ciGetChannelCallbacks(chat, target); if((callbacks != NULL) && (callbacks->channelMessage != NULL)) { ciCallbackChannelMessageParams params; params.channel = target; if(message->nick != NULL) params.user = message->nick; else params.user = NULL; params.message = msg; params.type = CHAT_ATM; ciAddCallback(chat, CALLBACK_CHANNEL_MESSAGE, (void*)callbacks->channelMessage, ¶ms, callbacks->param, 0, target); } } } void ciPingHandler(CHAT chat, const ciServerMessage * message) { CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciPingHandler called\n"); #endif ciSocketSendf(&connection->chatSocket, "PONG %s", message->param); } void ciNickHandler(CHAT chat, const ciServerMessage * message) { char * oldNick; char * newNick; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciNickHandler called\n"); #endif assert(message->numParams == 1); if(message->numParams != 1) return; //ERRCON oldNick = message->nick; newNick = message->params[0]; // Is this me? ////////////// if(strcasecmp(oldNick, connection->nick) == 0) { ciServerMessageFilter * filter; ciFilterMatch match; // Copy the new nick. ///////////////////// assert(strlen(newNick) < MAX_NICK); strzcpy(connection->nick, newNick, MAX_NICK); // Copy to the unicode version #ifdef GSI_UNICODE AsciiToUCS2String(connection->nick, connection->nickW); #endif // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_NICK; match.name = oldNick; match.name2 = newNick; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { // Add the callback. //////////////////// ciCallbackChangeNickParams params; params.success = CHATTrue; params.oldNick = oldNick; params.newNick = newNick; FINISH_FILTER; } } // Change the nick. /////////////////// ciUserChangedNick(chat, oldNick, newNick); } void ciJoinHandler(CHAT chat, const ciServerMessage * message) { char * channel; char * nick; char * user; char * address; int mode; chatChannelCallbacks * callbacks; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciJoinHandler called\n"); #endif assert(message->numParams == 1); if(message->numParams != 1) return; //ERRCON channel = message->params[0]; nick = message->nick; user = message->user; address = message->host; // Check for mode. ////////////////// if(*nick == '@') { mode = CHAT_OP; nick++; assert(*nick != '\0'); } else if(*nick == '+') { mode = CHAT_VOICE; nick++; assert(*nick != '\0'); } else { mode = CHAT_NORMAL; } // Me? ////// if(strcmp(nick, connection->nick) == 0) { ciServerMessageFilter * filter; ciFilterMatch match; // Make sure we're entering this channel. ///////////////////////////////////////// if(!ciIsEnteringChannel(chat, channel)) return; // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; // Look for a matching filter. ////////////////////////////// filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { JOINData * data; // Get the data. //////////////// data = (JOINData *)filter->data; // Add the channel. /////////////////// ciChannelEntered(chat, channel, &data->callbacks); // Set the password. //////////////////// ciSetChannelPassword(chat, channel, data->password); // Joined. ////////// data->joined = CHATTrue; // Get the channel's mode. ////////////////////////// ciSocketSendf(&connection->chatSocket, "MODE %s", channel); } return; } // Add the user to the channel. /////////////////////////////// if(ciInChannel(chat, channel)) ciUserEnteredChannel(chat, nick, channel, mode, user, address); // Was the join callback called? //////////////////////////////// if(ciWasJoinCallbackCalled(chat, channel)) //PANTS - 03.01.00 - check if the join callback was called { // Call the join callback. ////////////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks != NULL) { if(callbacks->userJoined != NULL) { ciCallbackUserJoinedParams params; params.channel = channel; params.user = nick; params.mode = mode; ciAddCallback(chat, CALLBACK_USER_JOINED, (void*)callbacks->userJoined, ¶ms, callbacks->param, 0, channel); } // Call the user list updated callback. /////////////////////////////////////// if(callbacks->userListUpdated != NULL) { ciCallbackUserListUpdatedParams params; params.channel = channel; ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); } } } } void ciPartHandler(CHAT chat, const ciServerMessage * message) { char * nick; char * channel; char * reason; chatChannelCallbacks * callbacks; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciPartHandler called\n"); #endif nick = message->nick; channel = message->params[0]; if (message->numParams > 1) //get the reason reason = message->params[1]; else reason = ""; // Did we leave the channel? //////////////////////////// if(strcmp(nick, connection->nick) == 0) { // Ignore it, we already left. ////////////////////////////// } else { // Remove the user from the channel. //////////////////////////////////// ciUserLeftChannel(chat, nick, channel); // Was the join callback called? //////////////////////////////// if(ciWasJoinCallbackCalled(chat, channel)) { // Call the left callback. ////////////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks != NULL) { if(callbacks->userParted != NULL) { ciCallbackUserPartedParams params; params.channel = channel; params.user = nick; params.why = CHAT_LEFT; params.reason = reason; params.kicker = NULL; ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); } // Call the user list updated callback. /////////////////////////////////////// if(callbacks->userListUpdated != NULL) { ciCallbackUserListUpdatedParams params; params.channel = channel; ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); } } } } } void ciKickHandler(CHAT chat, const ciServerMessage * message) { char * channel; char * kicker; char * kickee; char * reason; chatChannelCallbacks * callbacks; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciKickHandler called\n"); #endif assert((message->numParams == 2) || (message->numParams == 3)); if((message->numParams != 2) && (message->numParams != 3)) return; //ERRCON channel = message->params[0]; kicker = message->nick; kickee = message->params[1]; if(message->numParams == 3) reason = message->params[2]; else reason = ""; // Remove the user from the channel. //////////////////////////////////// ciUserLeftChannel(chat, kickee, channel); // Get the callbacks. ///////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks != NULL) { // Check if we were kicked. /////////////////////////// if(strcasecmp(kickee, connection->nick) == 0) { // Add the callback. //////////////////// if(callbacks->kicked != NULL) { ciCallbackKickedParams params; params.channel = channel; params.user = kicker; params.reason = reason; ciAddCallback(chat, CALLBACK_KICKED, (void*)callbacks->kicked, ¶ms, callbacks->param, 0, NULL); } // Left the channel. //////////////////// ciChannelLeft(chat, channel); } else { // Was the join callback called? //////////////////////////////// if(ciWasJoinCallbackCalled(chat, channel)) { // Add the callback. //////////////////// if(callbacks->userParted != NULL) { ciCallbackUserPartedParams params; params.channel = channel; params.user = kickee; params.why = CHAT_KICKED; params.reason = reason; params.kicker = kicker; ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); } // Call the user list updated callback. /////////////////////////////////////// if(callbacks->userListUpdated != NULL) { ciCallbackUserListUpdatedParams params; params.channel = channel; ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); } } } } } static void ciQuitEnumChannelsCallback(CHAT chat, const char * user, const char * channel, void * reason) { chatChannelCallbacks * callbacks; ASSERT_STR(user); ASSERT_STR(channel); assert(reason != NULL); // Remove the user from the channel. //////////////////////////////////// ciUserLeftChannel(chat, user, channel); // Was the join callback called? //////////////////////////////// if(ciWasJoinCallbackCalled(chat, channel)) { // Get the channel callbacks. ///////////////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks != NULL) { // Call the quit callback. ////////////////////////// if(callbacks->userParted != NULL) { ciCallbackUserPartedParams params; params.channel = (char *)channel; params.user = (char *)user; params.why = CHAT_QUIT; params.reason = (char *)reason; params.kicker = NULL; ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); } // Call the user list updated callback. /////////////////////////////////////// if(callbacks->userListUpdated != NULL) { ciCallbackUserListUpdatedParams params; params.channel = (char *)channel; ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); } } } } void ciQuitHandler(CHAT chat, const ciServerMessage * message) { char * reason; //CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciQuitHandler called\n"); #endif assert(message->numParams == 1); if(message->numParams != 1) return; //ERRCON reason = message->params[0]; // Enum the channels this user is in. ///////////////////////////////////// ciUserEnumChannels(chat, message->nick, ciQuitEnumChannelsCallback, reason); } static void ciKillEnumChannelsCallback(CHAT chat, const char * user, const char * channel, void * param) { chatChannelCallbacks * callbacks; char *reason = (char *)param; ASSERT_STR(user); ASSERT_STR(channel); assert(reason != NULL); // Remove the user from the channel. //////////////////////////////////// ciUserLeftChannel(chat, user, channel); // Was the join callback called? //////////////////////////////// if(ciWasJoinCallbackCalled(chat, channel)) { // Get the channel callbacks. ///////////////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks != NULL) { if(callbacks->userParted != NULL) { ciCallbackUserPartedParams params; params.channel = (char *)channel; params.user = (char *)user; params.why = CHAT_KILLED; params.reason = (char *)reason; params.kicker = NULL; ciAddCallback(chat, CALLBACK_USER_PARTED, (void*)callbacks->userParted, ¶ms, callbacks->param, 0, channel); } // Call the user list updated callback. /////////////////////////////////////// if(callbacks->userListUpdated != NULL) { ciCallbackUserListUpdatedParams params; params.channel = (char *)channel; ciAddCallback(chat, CALLBACK_USER_LIST_UPDATED, (void*)callbacks->userListUpdated, ¶ms, callbacks->param, 0, channel); } } } } void ciKillHandler(CHAT chat, const ciServerMessage * message) { char * nick; char * reason; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciKillHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON nick = message->params[0]; reason = message->params[1]; // Enum the channels this user is in. ///////////////////////////////////// ciUserEnumChannels(chat, nick, ciKillEnumChannelsCallback, reason); } void ciTopicHandler(CHAT chat, const ciServerMessage * message) { char * channel; char * topic; chatChannelCallbacks * callbacks; //CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciTopicHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON channel = message->params[0]; topic = message->params[1]; // Set the channel's topic. /////////////////////////// ciSetChannelTopic(chat, channel, topic); // Get the callbacks. ///////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if((callbacks != NULL) && (callbacks->topicChanged != NULL)) { ciCallbackTopicChangedParams params; params.channel = channel; params.topic = topic; ciAddCallback(chat, CALLBACK_TOPIC_CHANGED, (void*)callbacks->topicChanged, ¶ms, callbacks->param, 0, channel); } } void ciModeHandler(CHAT chat, const ciServerMessage * message) { ciModeChange * changes; ciModeChange * change; CHATChannelMode channelMode; char * channel; char * mode; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciModeHandler called\n"); #endif assert(message->numParams >= 2); if(message->numParams < 2) return; //ERRCON channel = message->params[0]; mode = message->params[1]; // Check that we're in this channel. //////////////////////////////////// if(!ciInChannel(chat, channel)) return; // Parse the changes. ///////////////////// changes = ciParseMode(mode, message->params + 2, message->numParams - 2); if(changes == NULL) return; //ERRCON // Go through all the changes. ////////////////////////////// for(change = changes ; change->mode != MODE_END ; change++) { switch(change->mode) { case MODE_BAN: break; case MODE_INVITE_ONLY: break; case MODE_LIMIT: break; case MODE_PRIVATE: break; case MODE_SECRET: break; case MODE_KEY: if(change->enable) ciSetChannelPassword(chat, channel, change->param); else ciSetChannelPassword(chat, channel, NULL); break; case MODE_MODERATED: break; case MODE_NO_EXTERNAL_MESSAGES: break; case MODE_ONLY_OPS_CHANGE_TOPIC: break; case MODE_USERS_HIDDEN: break; case MODE_RECEIVE_WALLOPS: break; case MODE_OP: if(change->param) ciUserChangedMode(chat, change->param, channel, CHAT_OP, change->enable); break; case MODE_VOICE: if(change->param) ciUserChangedMode(chat, change->param, channel, CHAT_VOICE, change->enable); break; case MODE_OPS_OBEY_CHANNEL_LIMIT: break; default: assert(0); } } // Apply the changes to the mode. ///////////////////////////////// if(!ciGetChannelMode(chat, channel, &channelMode)) { gsifree(changes); return; //ERRCON } ciApplyChangesToMode(&channelMode, changes); ciSetChannelMode(chat, channel, &channelMode); // gsifree the changes. //////////////////// gsifree(changes); } void ciErrorHandler(CHAT chat, const ciServerMessage * message) { //CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrorHandler called\n"); #endif assert(message->numParams == 1); if(message->numParams != 1) return; //ERRCON // Handle the disconnection. //////////////////////////// ciHandleDisconnect(chat, message->params[0]); } void ciInviteHandler(CHAT chat, const ciServerMessage * message) { char * nick; char * channel; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciInviteHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; //ERRCON // Get info. //////////// nick = message->nick; channel = message->params[1]; // Call the invite callback. //////////////////////////// if(connection->globalCallbacks.invited != NULL) { ciCallbackInvitedParams params; params.channel = channel; params.user = nick; ciAddCallback(chat, CALLBACK_INVITED, (void*)connection->globalCallbacks.invited, ¶ms, connection->globalCallbacks.param, 0, NULL); } } void ciNameReplyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch matches[4]; ciServerMessageFilter * filter; char * channel; NAMESData * data = NULL; char * names; char * nick; char * str; void * tempPtr; int mode; int len; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciNameReplyHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON channel = message->params[2]; names = message->params[3]; // Setup the filter matches. //////////////////////////// memset(matches, 0, sizeof(matches)); matches[0].type = TYPE_JOIN; matches[0].name = channel; matches[1].type = TYPE_UNQUIET; matches[1].name = channel; matches[2].type = TYPE_NAMES; matches[2].name = channel; matches[3].type = TYPE_NAMES; // Check for a matching filter. /////////////////////////////// filter = ciFindFilter(chat, 4, matches); if(!filter) return; // Get the data. //////////////// if(filter->type != TYPE_JOIN) data = (NAMESData *)filter->data; // Parse out the names. /////////////////////// nick = strtok(names, " "); while(nick != NULL) { assert(nick[0] != '\0'); // Check the mode. ////////////////// if(nick[0] == '@') { assert(nick[1] != '\0'); mode = CHAT_OP; nick++; } else if(nick[0] == '+') { assert(nick[1] != '\0'); mode = CHAT_VOICE; nick++; } else mode = CHAT_NORMAL; if(filter->type != TYPE_JOIN) { // Check for resize. //////////////////// if(data->numUsers == data->len) { tempPtr = (char **)gsirealloc(data->users, sizeof(char *) * (data->len + NAMES_ARRAY_INC)); if(tempPtr == NULL) { assert(0); return; //ERRCON } data->users = (char **)tempPtr; tempPtr = (char **)gsirealloc(data->modes, sizeof(int) * (data->len + NAMES_ARRAY_INC)); if(tempPtr == NULL) { assert(0); return; //ERRCON } data->modes = (int *)tempPtr; data->len += NAMES_ARRAY_INC; } // Allocate mem for the nick. ///////////////////////////// len = (int)(strlen(nick) + 1); str = (char *)gsimalloc((unsigned int)len); if(str == NULL) { assert(0); return; //ERRCON } memcpy(str, nick, (unsigned int)len); // Set the pointers. //////////////////// data->users[data->numUsers] = str; data->modes[data->numUsers] = mode; data->numUsers++; } if((filter->type == TYPE_JOIN) || (filter->type == TYPE_UNQUIET)) { // Add the nick to the channel. /////////////////////////////// ciUserEnteredChannel(chat, nick, channel, mode, NULL, NULL); } // Get the next nick. ///////////////////// nick = strtok(NULL, " "); } } void ciEndOfNamesHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch matches[4]; ciServerMessageFilter * filter; char * channel; //CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciEndOfNamesHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Check for the special case "all channels". ///////////////////////////////////////////// if(strcmp(channel, "*") == 0) channel = NULL; // Setup the filter matches. //////////////////////////// memset(matches, 0, sizeof(matches)); matches[0].type = TYPE_JOIN; matches[0].name = channel; matches[1].type = TYPE_UNQUIET; matches[1].name = channel; matches[2].type = TYPE_NAMES; matches[2].name = channel; matches[3].type = TYPE_NAMES; // Look for a matching filter. ////////////////////////////// filter = ciFindFilter(chat, 4, matches); if(!filter) return; // Join filter? /////////////// if(filter->type == TYPE_JOIN) { ciCallbackEnterChannelParams params; params.success = CHATTrue; params.result = CHATEnterSuccess; params.channel = channel; if(!filter->callback) { // There's no callback, so set the callback called flag now. //////////////////////////////////////////////////////////// ciJoinCallbackCalled(chat, channel); } FINISH_FILTER; return; } // Unquiet filter? //////////////////// if(filter->type == TYPE_UNQUIET) { NAMESData * data = (NAMESData *)filter->data; ciCallbackNewUserListParams params; params.channel = channel; params.numUsers = data->numUsers; params.users = data->users; params.modes = data->modes; FINISH_FILTER; return; } // Names filter? //////////////// if(filter->type == TYPE_NAMES) { NAMESData * data = (NAMESData *)filter->data; ciCallbackEnumUsersParams params; params.success = CHATTrue; params.channel = channel; params.numUsers = data->numUsers; params.users = data->users; params.modes = data->modes; FINISH_FILTER; return; } } void ciRplTopicHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * topic; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplTopicHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON channel = message->params[1]; topic = message->params[2]; // Set the channel's topic. /////////////////////////// ciSetChannelTopic(chat, channel, topic); // Setup a filter match. //////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_TOPIC; match.name = channel; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackGetChannelTopicParams params; params.success = CHATTrue; params.channel = channel; params.topic = topic; FINISH_FILTER; } else { // No filter, probably checking the topic on join. ////////////////////////////////////////////////// chatChannelCallbacks * callbacks; callbacks = ciGetChannelCallbacks(chat, channel); if((callbacks != NULL) && (callbacks->topicChanged != NULL)) { ciCallbackTopicChangedParams params; params.channel = channel; params.topic = topic; ciAddCallback(chat, CALLBACK_TOPIC_CHANGED, (void*)callbacks->topicChanged, ¶ms, callbacks->param, 0, channel); } } } void ciRplNoTopicHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplNoTopicHandler called\n"); #endif assert(message->numParams >= 2); if(message->numParams < 2) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_TOPIC; match.name = channel; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackGetChannelTopicParams params; params.success = CHATTrue; params.channel = channel; params.topic = ""; FINISH_FILTER; } else { // No filter, probably checking the topic on join. ////////////////////////////////////////////////// chatChannelCallbacks * callbacks; callbacks = ciGetChannelCallbacks(chat, channel); if((callbacks != NULL) && (callbacks->topicChanged != NULL)) { ciCallbackTopicChangedParams params; params.channel = channel; params.topic = ""; ciAddCallback(chat, CALLBACK_TOPIC_CHANGED, (void*)callbacks->topicChanged, ¶ms, callbacks->param, 0, channel); } } } void ciErrNickInUseHandler(CHAT chat, const ciServerMessage * message) { char * oldNick; char * newNick; ciServerMessageFilter * filter; ciFilterMatch match; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplNickErrorHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON oldNick = message->params[0]; newNick = message->params[1]; // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_NICK; match.name = oldNick; match.name2 = newNick; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { // Add the callback. //////////////////// ciCallbackChangeNickParams params; params.success = CHATFalse; params.oldNick = oldNick; params.newNick = newNick; FINISH_FILTER; } else { // We should be connecting. ////////////////////////// assert(connection->connecting); if(connection->connecting) ciNickError(chat, CHAT_IN_USE, connection->nick, 0, NULL); } } void ciRplWhoReplyHandler(CHAT chat, const ciServerMessage * message) { char * channel; char * nick; char * user; char * address; ciServerMessageFilter * filter; ciFilterMatch matches[3]; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplWhoReplyHandler called\n"); #endif assert(message->numParams == 8); if(message->numParams != 8) return; //ERRCON channel = message->params[1]; user = message->params[2]; address = message->params[3]; nick = message->params[5]; // Cache the user and address. ////////////////////////////// ciSetUserBasicInfo(chat, nick, user, address); // Setup the filter matches. //////////////////////////// memset(matches, 0, sizeof(matches)); matches[0].type = TYPE_UMODE; matches[0].name = nick; matches[0].name2 = channel; matches[1].type = TYPE_WHO; matches[1].name = nick; matches[2].type = TYPE_CWHO; matches[2].name = channel; // Find the filter. /////////////////// filter = ciFindFilter(chat, 3, matches); if(!filter) return; // User mode filter? //////////////////// if(filter->type == TYPE_UMODE) { ciCallbackGetUserModeParams params; int mode; // Check the mode. ////////////////// mode = 0; if(strchr(message->params[6], '@')) mode |= CHAT_OP; if(strchr(message->params[6], '+')) mode |= CHAT_VOICE; params.success = CHATTrue; params.channel = channel; params.user = nick; params.mode = mode; FINISH_FILTER; return; } // Who filter? ////////////// if(filter->type == TYPE_WHO) { ciCallbackGetBasicUserInfoParams params; params.success = CHATTrue; params.nick = nick; params.user = user; params.address = address; ciAddCallback(chat, CALLBACK_GET_BASIC_USER_INFO, filter->callback, ¶ms, filter->param, filter->ID, NULL); // We want to wait until we get the end, but we've already called the callback. /////////////////////////////////////////////////////////////////////////////// filter->callback = NULL; return; } // Who filter? ////////////// if((filter->type == TYPE_CWHO) && filter->callback) { ciCallbackGetChannelBasicUserInfoParams params; params.success = CHATTrue; params.channel = filter->name; params.nick = nick; params.user = user; params.address = address; ciAddCallback(chat, CALLBACK_GET_CHANNEL_BASIC_USER_INFO, filter->callback, ¶ms, filter->param, filter->ID, NULL); return; } } void ciRplEndOfWhoHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch matches[2]; ciServerMessageFilter * filter; char * name; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplEndOfWhoHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON name = message->params[1]; // Setup the filter matches. //////////////////////////// memset(matches, 0, sizeof(matches)); matches[0].type = TYPE_WHO; matches[0].name = name; matches[1].type = TYPE_CWHO; matches[1].name = name; // Find the filter. /////////////////// filter = ciFindFilter(chat, 2, matches); if(!filter) return; // Who filter? ////////////// if(filter->type == TYPE_WHO) { ciCallbackGetBasicUserInfoParams params; params.success = CHATFalse; params.nick = name; params.user = NULL; params.address = NULL; FINISH_FILTER; return; } // Channel who filter? ////////////////////// if(filter->type == TYPE_CWHO) { ciCallbackGetChannelBasicUserInfoParams params; params.success = CHATTrue; params.channel = name; params.nick = NULL; params.user = NULL; params.address = NULL; FINISH_FILTER; return; } } static char * ciParseValue(const char * flags, int * len) { int i; char * str; assert(flags); assert(len); // First should be a '\'. ///////////////////////// if(!flags || (flags[0] != '\\')) return NULL; // Skip it. /////////// flags++; // Find the end of the value. ///////////////////////////// for(i = 0 ; flags[i] && (flags[i] != '\\') ; i++) { }; // Allocate it. /////////////// str = (char *)gsimalloc((unsigned int)i + 1); if(!str) return NULL; // Copy it in. ////////////// memcpy(str, flags, (unsigned int)i); str[i] = '\0'; // Return it. ///////////// *len = (i + 1); return str; } void ciRplGetKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; const char * nick; const char * cookie; const char * flags; int num; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplGetKeyHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON nick = message->params[1]; cookie = message->params[2]; flags = message->params[3]; // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETKEY; match.name = cookie; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { GETKEYData * data; ciCallbackGetGlobalKeysParams params; char ** values; char * str; int i; int len; data = (GETKEYData *)filter->data; num = data->num; // Allocate the values. /////////////////////// values = (char **)gsimalloc(sizeof(char *) * num); if(!values) return; // Parse them out. ////////////////// for(i = 0 ; i < num ; i++) { str = ciParseValue(flags, &len); if(str) { values[i] = str; flags += len; } else { values[i] = goastrdup(""); } } // Setup the callback parameters. ///////////////////////////////// params.success = CHATTrue; params.user = (char *)nick; params.num = num; params.keys = data->keys; params.values = values; // If this is a 1-user get, we're finished. /////////////////////////////////////////// if(!data->channel) { FINISH_FILTER; } else { ciAddCallback(chat, CALLBACK_GET_GLOBAL_KEYS, filter->callback, ¶ms, filter->param, filter->ID, NULL); } for(i = 0 ; i < num ; i++) gsifree(values[i]); gsifree(values); } } void ciRplEndGetKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; const char * cookie; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplEndGetKeyHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON cookie = message->params[2]; // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETKEY; match.name = cookie; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { ciCallbackGetGlobalKeysParams params; GETKEYData * data; data = (GETKEYData *)filter->data; // Setup the callback parameters. ///////////////////////////////// params.success = CHATTrue; params.user = NULL; params.num = data->num; params.keys = data->keys; params.values = NULL; FINISH_FILTER; } } void ciRplGetCKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; const char * nick; const char * cookie; char * flags; const char * channel; int num; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplGetCKeyHandler called\n"); #endif assert(message->numParams == 5); if(message->numParams != 5) return; //ERRCON channel = message->params[1]; nick = message->params[2]; cookie = message->params[3]; flags = message->params[4]; // Check for a broadcast update. //////////////////////////////// if(strcmp(cookie, "BCAST") == 0) { chatChannelCallbacks * callbacks; ciCallbackBroadcastKeyChangedParams params; char * key; char * value; int temp; callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks && callbacks->broadcastKeyChanged) { memset(¶ms, 0, sizeof(ciCallbackBroadcastKeyChangedParams)); params.channel = (char *)channel; params.user = (char *)nick; while(*flags) { key = strstr(flags, "b_"); flags = key; while(*flags && (*flags != '\\')) flags++; if(!*flags) break; *flags++ = '\0'; value = flags; while(*flags && (*flags != '\\')) flags++; temp = *flags; *flags = '\0'; // Call the callback. ///////////////////// params.key = key; params.value = value; ciAddCallback(chat, CALLBACK_BROADCAST_KEY_CHANGED, (void*)callbacks->broadcastKeyChanged, ¶ms, callbacks->param, 0, channel); *flags = (char)temp; } } return; } // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETCKEY; match.name = cookie; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { GETCKEYData * data; ciCallbackGetChannelKeysParams params; char ** values; char * key; char * value; int i; int len; char ** tempPtr; data = (GETCKEYData *)filter->data; num = data->num; // Allocate the values. /////////////////////// values = (char **)gsimalloc(sizeof(char *) * num); if(!values) return; // Parse them out. ////////////////// for(i = 0 ; i < num ; i++) { value = ciParseValue(flags, &len); values[i] = value; if(value) flags += len; } // Do we need to do b_* stuff? ////////////////////////////// if(data->allBroadcastKeys) { while((key = ciParseValue(flags, &len)) != NULL) { flags += len; value = ciParseValue(flags, &len); if(value) { flags += len; // Add this key and value to our list. ////////////////////////////////////// tempPtr = (char **)gsirealloc(data->keys, sizeof(char *) * (num + 1)); if(tempPtr) { data->keys = tempPtr; tempPtr = (char **)gsirealloc(values, sizeof(char *) * (num + 1)); if(tempPtr) { values = tempPtr; data->keys[num] = key; values[num] = value; num++; } else { gsifree(key); gsifree(value); } } else { gsifree(key); gsifree(value); } } else { gsifree(key); break; } } // The new number of keys. ////////////////////////// data->num = num; } // Setup the callback parameters. ///////////////////////////////// params.success = CHATTrue; params.channel = (char *)channel; params.user = (char *)nick; params.num = num; params.keys = data->keys; params.values = values; // If this is a 1-user get, we're finished. /////////////////////////////////////////// if(!data->channel) { FINISH_FILTER; } else { ciAddCallback(chat, CALLBACK_GET_CHANNEL_KEYS, filter->callback, ¶ms, filter->param, filter->ID, NULL); } for(i = 0 ; i < num ; i++) gsifree(values[i]); gsifree(values); } } void ciRplEndGetCKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; const char * cookie; const char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplEndGetCKeyHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON channel = message->params[1]; cookie = message->params[2]; // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETCKEY; match.name = cookie; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { GETCKEYData * data; ciCallbackGetChannelKeysParams params; data = (GETCKEYData *)filter->data; // Setup the callback parameters. ///////////////////////////////// params.success = CHATTrue; params.channel = (char *)channel; params.user = NULL; params.num = data->num; params.keys = data->keys; params.values = NULL; FINISH_FILTER; } } void ciRplGetChanKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; const char * cookie; char * flags; const char * channel; int num; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplGetChanKeyHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON channel = message->params[1]; cookie = message->params[2]; flags = message->params[3]; // Check for a broadcast update. //////////////////////////////// if(strcmp(cookie, "BCAST") == 0) { chatChannelCallbacks * callbacks; ciCallbackBroadcastKeyChangedParams params; char * key; char * value; int temp; callbacks = ciGetChannelCallbacks(chat, channel); if(callbacks && callbacks->broadcastKeyChanged) { memset(¶ms, 0, sizeof(ciCallbackBroadcastKeyChangedParams)); params.channel = (char *)channel; params.user = NULL; while(*flags) { key = strstr(flags, "b_"); flags = key; while(*flags && (*flags != '\\')) flags++; if(!*flags) break; *flags++ = '\0'; value = flags; while(*flags && (*flags != '\\')) flags++; temp = *flags; *flags = '\0'; // Call the callback. ///////////////////// params.key = key; params.value = value; ciAddCallback(chat, CALLBACK_BROADCAST_KEY_CHANGED, (void*)callbacks->broadcastKeyChanged, ¶ms, callbacks->param, 0, channel); *flags = (char)temp; } } return; } // Setup the filter match. ////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETCHANKEY; match.name = cookie; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { GETCHANKEYData * data; ciCallbackGetChannelKeysParams params; char ** values; char ** keys = NULL; char * key; char * value; int i; int len; char ** tempPtr; data = (GETCHANKEYData *)filter->data; num = data->num; // Allocate the values. /////////////////////// if(num) { values = (char **)gsimalloc(sizeof(char *) * num); if(!values) return; // Parse them out. ////////////////// for(i = 0 ; i < num ; i++) { value = ciParseValue(flags, &len); values[i] = value; if(value) flags += len; } // Do we need to do b_* stuff? ////////////////////////////// if(data->allBroadcastKeys) { while((key = ciParseValue(flags, &len)) != NULL) { flags += len; value = ciParseValue(flags, &len); if(value) { flags += len; // Add this key and value to our list. ////////////////////////////////////// tempPtr = (char **)gsirealloc(data->keys, sizeof(char *) * (num + 1)); if(tempPtr) { data->keys = tempPtr; tempPtr = (char **)gsirealloc(values, sizeof(char *) * (num + 1)); if(tempPtr) { values = tempPtr; data->keys[num] = key; values[num] = value; num++; } else { gsifree(key); gsifree(value); } } else { gsifree(key); gsifree(value); } } else { gsifree(key); break; } } // The new number of keys. ////////////////////////// data->num = num; } } else { char ** keysTemp; char ** valuesTemp; keys = NULL; values = NULL; num = 0; while(1) { key = ciParseValue(flags, &len); if(!key) break; flags += len; value = ciParseValue(flags, &len); if(!value) { gsifree(key); break; } flags += len; keysTemp = (char **)gsirealloc(keys, sizeof(char *) * (num + 1)); valuesTemp = (char **)gsirealloc(values, sizeof(char *) * (num + 1)); if(!keysTemp || !valuesTemp) { gsifree(key); gsifree(value); while(num--) { gsifree(keys[num]); gsifree(values[num]); } if(keysTemp) gsifree(keysTemp); else gsifree(keys); if(valuesTemp) gsifree(valuesTemp); else gsifree(values); } keys = keysTemp; keys[num] = key; values = valuesTemp; values[num] = value; num++; } data->num = num; data->keys = keys; } // Setup the callback parameters. ///////////////////////////////// params.success = CHATTrue; params.channel = (char *)channel; params.user = NULL; params.num = num; params.keys = data->keys; params.values = values; FINISH_FILTER; for(i = 0 ; i < num ; i++) gsifree(values[i]); gsifree(values); } } void ciRplUserIPHandler(CHAT chat, const ciServerMessage * message) { char * IP; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplUserIPHandler called\n"); #endif assert(message->numParams >= 1); if(message->numParams < 1) return; //ERRCON IP = strchr(message->params[message->numParams - 1], '@'); if(IP) { IP++; if(connection->fillInUserCallback) { #ifndef GSI_UNICODE char user[MAX_USER]; connection->fillInUserCallback(chat, inet_addr(IP), user, connection->connectParam); strzcpy(connection->user, user, MAX_USER); #else unsigned short user[MAX_USER]; connection->fillInUserCallback(chat, inet_addr(IP), user, connection->connectParam); wcszcpy(connection->userW, user, MAX_USER); // copy the unicode version UCS2ToAsciiString(user, connection->user); // convert the unicode user to ascii (nicknames cannot currently be UTF-8!!) #endif } } // Send the nick and user. ////////////////////////// ciSendNickAndUser(chat); } void ciRplListStartHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplListStartHandler called\n"); #endif memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_LIST; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { LISTData * data = (LISTData *)filter->data; assert(data != NULL); //assert(!data->gotStart); data->gotStart = CHATTrue; } GSI_UNUSED(message); } void ciRplListHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplListHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_LIST; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { if(filter->callback != NULL) { ciCallbackEnumChannelsEachParams params; int index; char * channel; int numUsers; char * topic; int len; void * tempPtr; LISTData * data = (LISTData *)filter->data; assert(data != NULL); //assert(data->gotStart); // Get the channel. /////////////////// len = (int)(strlen(message->params[1]) + 1); channel = (char *)gsimalloc((unsigned int)len); if(channel == NULL) return; //ERRCON memcpy(channel, message->params[1], (unsigned int)len); // Get the num users. ///////////////////// numUsers = atoi(message->params[2]); // Get the topic. ///////////////// len = (int)(strlen(message->params[3]) + 1); topic = (char *)gsimalloc((unsigned int)len); if(topic == NULL) { gsifree(channel); return; //ERRCON } memcpy(topic, message->params[3], (unsigned int)len); // Get the index. ///////////////// index = data->numChannels; // Add the callback. //////////////////// params.success = CHATTrue; params.index = index; params.channel = channel; params.topic = topic; params.numUsers = numUsers; ciAddCallback(chat, CALLBACK_ENUM_CHANNELS_EACH, filter->callback, ¶ms, filter->param, filter->ID, NULL); //TODO:only store this stuff if there's an "all" callback // Add the channel. /////////////////// tempPtr = gsirealloc(data->channels, sizeof(char *) * (data->numChannels + 1)); if(tempPtr == NULL) { gsifree(channel); gsifree(topic); return; //ERRCON } data->channels = (char **)tempPtr; data->channels[index] = channel; // Add the numUsers. //////////////////// tempPtr = gsirealloc(data->numUsers, sizeof(int) * (data->numChannels + 1)); if(tempPtr == NULL) { gsifree(channel); gsifree(topic); return; //ERRCON } data->numUsers = (int *)tempPtr; data->numUsers[index] = numUsers; // Add the topic. ///////////////// tempPtr = gsirealloc(data->topics, sizeof(char *) * (data->numChannels + 1)); if(tempPtr == NULL) { gsifree(channel); gsifree(topic); return; //ERRCON } data->topics = (char **)tempPtr; data->topics[index] = topic; // One more channel. //////////////////// data->numChannels++; } } } void ciRplListEndHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplListEndHandler called\n"); #endif memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_LIST; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { LISTData * data = (LISTData *)filter->data; ciCallbackEnumChannelsAllParams params; params.success = CHATTrue; params.numChannels = data->numChannels; params.channels = data->channels; params.numUsers = data->numUsers; params.topics = data->topics; FINISH_FILTER; } GSI_UNUSED(message); } void ciRplChannelModeIsHandler(CHAT chat, const ciServerMessage * message) { char * channel; char * modes; ciModeChange * changes; CHATChannelMode mode; CHATChannelMode dummyMode; ciServerMessageFilter * filter; ciFilterMatch match; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplChannelModeIs called\n"); #endif assert(message->numParams >=3); if(message->numParams < 3) return; //ERRCON channel = message->params[1]; modes = message->params[2]; // Parse the mode. ////////////////// changes = ciParseMode(modes, message->params + 3, message->numParams - 3); if(changes == NULL) return; //ERRCON // Fill the mode struct. //////////////////////// memset(&mode, 0, sizeof(CHATChannelMode)); ciApplyChangesToMode(&mode, changes); // Check if we have this channel's mode. //////////////////////////////////////// if(!ciGetChannelMode(chat, channel, &dummyMode)) { chatChannelCallbacks * callbacks; // Set the mode. //////////////// ciSetChannelMode(chat, channel, &mode); // Mode changed callback? ///////////////////////// callbacks = ciGetChannelCallbacks(chat, channel); if((callbacks != NULL) && (callbacks->channelModeChanged != NULL)) { ciCallbackChannelModeChangedParams params; params.channel = channel; params.mode = &mode; ciAddCallback(chat, CALLBACK_CHANNEL_MODE_CHANGED, (void*)callbacks->channelModeChanged, ¶ms, callbacks->param, 0, channel); } } // Were we waiting for this? //////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_CMODE; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackGetChannelModeParams params; params.success = CHATTrue; params.channel = channel; params.mode = &mode; FINISH_FILTER; } // gsifree the changes. //////////////////// gsifree(changes); } void ciRplWhoisUserHandler(CHAT chat, const ciServerMessage * message) { char * nick; ciFilterMatch matches[2]; ciServerMessageFilter * filter; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplWhoisUserHandler called\n"); #endif assert(message->numParams == 6); if(message->numParams != 6) return; //ERRCON // Get the nick. //////////////// nick = message->params[1]; // Setup the filter matches. //////////////////////////// memset(matches, 0, sizeof(matches)); matches[0].type = TYPE_WHOIS; matches[0].name = nick; matches[1].type = TYPE_BAN; matches[1].name = nick; // Find the filter. /////////////////// filter = ciFindFilter(chat, 2, matches); if(!filter) return; // Whois? ///////// if(filter->type == TYPE_WHOIS) { char * user; char * name; char * address; WHOISData * data = (WHOISData *)filter->data; // Cache the name and address pointers. /////////////////////////////////////// user = message->params[2]; name = message->params[5]; address = message->params[3]; // Copy the user. ///////////////// data->user = goastrdup(user); if(data->user == NULL) return; //ERRCON // Copy the name. ///////////////// data->name = goastrdup(name); if(data->name == NULL) return; //ERRCON // Copy the address. //////////////////// data->address = goastrdup(address); if(data->address == NULL) return; //ERRCON return; } // Ban? /////// if(filter->type == TYPE_BAN) { char * host; BANData * data = (BANData *)filter->data; assert(data != NULL); ASSERT_STR(data->channel); host = message->params[3]; // Ban this guy. //////////////// ciSocketSendf(&connection->chatSocket, "MODE %s +b *!*@%s", data->channel, host); ciFinishFilter(chat, filter, NULL); } } void ciRplWhoisChannelsHandler(CHAT chat, const ciServerMessage * message) { char * nick; ciServerMessageFilter * filter; ciFilterMatch match; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplWhoisChannelsHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the nick. //////////////// nick = message->params[1]; memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_WHOIS; match.name = nick; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { char * channels; char * str; char * channel; char ** tempPtr; WHOISData * data = (WHOISData *)filter->data; channels = message->params[2]; str = strtok(channels, " "); while(str != NULL) { // Check for deaf mode. /////////////////////// if(str[0] == '-') str++; // Check for op or voice. ///////////////////////// if((str[0] == '@') || (str[0] == '+')) str++; // Add it to the list. ////////////////////// channel = goastrdup(str); if(channel == NULL) return; //ERRCON tempPtr = (char **)gsirealloc(data->channels, sizeof(char *) * (data->numChannels + 1)); if(tempPtr == NULL) { gsifree(channel); return; //ERRCON } data->channels = tempPtr; data->channels[data->numChannels] = channel; data->numChannels++; // Get the next channel. //////////////////////// str = strtok(NULL, " "); } } } void ciRplEndOfWhoisHandler(CHAT chat, const ciServerMessage * message) { char * nick; ciServerMessageFilter * filter; ciFilterMatch match; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplEndOfWhoisHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the nick. //////////////// nick = message->params[1]; memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_WHOIS; match.name = nick; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { WHOISData * data = (WHOISData *)filter->data; ciCallbackGetUserInfoParams params; params.success = (CHATBool)(data->user != NULL); //PANTS|08.21.00 - false if nothing found params.nick = nick; params.user = data->user; params.name = data->name; params.address = data->address; params.numChannels = data->numChannels; params.channels = data->channels; FINISH_FILTER; } } void ciRplBanListHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; char * ban; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplBanListHandler called\n"); #endif assert(message->numParams >= 3); if(message->numParams < 3) return; //ERRCON channel = message->params[1]; ban = message->params[2]; // Look for a filter. ///////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETBAN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { int len; void * tempPtr; GETBANData * data = (GETBANData *)filter->data; assert(data != NULL); assert(data->numBans >= 0); // Increase the ban list. ///////////////////////// tempPtr = gsirealloc(data->bans, sizeof(char *) * (data->numBans + 1)); if(tempPtr == NULL) return; //ERRCON data->bans = (char **)tempPtr; // Add the new ban. /////////////////// len = (int)(strlen(ban) + 1); tempPtr = gsimalloc((unsigned int)len); if(tempPtr == NULL) return; //ERRCON memcpy(tempPtr, ban, (unsigned int)len); data->bans[data->numBans] = (char *)tempPtr; data->numBans++; } } void ciRplEndOfBanListHandler(CHAT chat, const ciServerMessage * message) { char * channel; ciServerMessageFilter * filter; ciFilterMatch match; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplEndOfBanListHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON channel = message->params[1]; // Look for a filter. ///////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETBAN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { GETBANData * data = (GETBANData *)filter->data; ciCallbackEnumChannelBansParams params; params.success = CHATTrue; params.channel = channel; params.numBans = data->numBans; params.bans = data->bans; FINISH_FILTER; } } void ciRplWelcomeHandler(CHAT chat, const ciServerMessage * message) { char * nick; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplWelcomeHandler called\n"); #endif assert(message->numParams == 2); if(message->numParams != 2) return; nick = message->params[0]; // Is the nick different? ///////////////////////// if(strcmp(connection->nick, nick) != 0) { strzcpy(connection->nick, nick, MAX_NICK); #ifdef GSI_UNICODE // store a unicode version AsciiToUCS2String(connection->nick, connection->nickW); #endif } // Connected. ///////////// connection->connecting = CHATFalse; connection->connected = CHATTrue; // Call the callback. ///////////////////// if(connection->connectCallback != NULL) connection->connectCallback(chat, CHATTrue, 0, connection->connectParam); } void ciRplSecureKeyHandler(CHAT chat, const ciServerMessage * message) { char * outKeyRand; char * inKeyRand; int outKeyLen; int inKeyLen; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplSecureKeyHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; outKeyRand = message->params[1]; inKeyRand = message->params[2]; // Take the random keys and the secret key to create the encoding/decoding keys. //////////////////////////////////////////////////////////////////////////////// outKeyLen = (int)strlen(outKeyRand); inKeyLen = (int)strlen(inKeyRand); gs_xcode_buf(outKeyRand, outKeyLen, connection->secretKey); gs_xcode_buf(inKeyRand, inKeyLen, connection->secretKey); gs_prepare_key((unsigned char *)outKeyRand, outKeyLen, &connection->chatSocket.outKey); gs_prepare_key((unsigned char *)inKeyRand, inKeyLen, &connection->chatSocket.inKey); // We now have a secure socket. /////////////////////////////// connection->chatSocket.secure = CHATTrue; // Login if we need to. /////////////////////// if(connection->loginType != CINoLogin) { ciSendLogin(chat); } // Get the IP if we need to. //////////////////////////// else if(connection->fillInUserCallback) { ciSocketSend(&connection->chatSocket, "USRIP"); } // Otherwise send the nick and user. //////////////////////////////////// else { ciSendNickAndUser(chat); } } void ciRplCDKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; int result; char * msg; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplCDKeyHandler called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; result = atoi(message->params[1]); msg = message->params[2]; // Setup a filter match. //////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_CDKEY; // Find the filter. /////////////////// filter = ciFindFilter(chat, 1, &match); if(filter) { ciCallbackAuthenticateCDKeyParams params; params.result = result; params.message = msg; FINISH_FILTER; } } void ciRplLoginHandler(CHAT chat, const ciServerMessage * message) { CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplLoginHandler called\n"); #endif assert(message->numParams >= 3); if(message->numParams < 3) return; // Store the ids. ///////////////// connection->userID = atoi(message->params[1]); connection->profileID = atoi(message->params[2]); // Get the IP if we need to. //////////////////////////// if(connection->fillInUserCallback) { ciSocketSend(&connection->chatSocket, "USRIP"); } // Otherwise send the nick and user. //////////////////////////////////// else { ciSendNickAndUser(chat); } } void ciRplGetUdpRelayHandler(CHAT chat, const ciServerMessage * message) { char *channel; int udpKey; char *udpIp; unsigned short udpPort; ciServerMessageFilter * filter; ciFilterMatch match; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciRplGetUdpRelayHandler called\n"); #endif assert(message->numParams >= 5); if(message->numParams < 5) return; channel = message->params[1]; udpKey = atoi(message->params[2]); udpIp = message->params[3]; udpPort = (unsigned short)atoi(message->params[4]); // Were we waiting for this? //////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_GETUDPRELAY; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackGetUdpRelayParams params; params.channel = channel; params.udpIp = udpIp; params.udpPort = udpPort; params.udpKey = udpKey; FINISH_FILTER; } } void ciErrNoSuchChannelHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch matches[2]; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrNoSuchChannel called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Setup the filter matches. //////////////////////////// memset(&matches, 0, sizeof(ciFilterMatch)); matches[0].type = TYPE_JOIN; matches[0].name = channel; matches[1].type = TYPE_CMODE; matches[1].name = channel; // Look for a matching filter. ////////////////////////////// filter = ciFindFilter(chat, 2, matches); if(filter) { // Join? //////// if(filter->type == TYPE_JOIN) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATBadChannelName; params.channel = channel; FINISH_FILTER; return; } // Channel mode? //////////////// if(filter->type == TYPE_CMODE) { ciCallbackGetChannelModeParams params; params.success = CHATFalse; params.channel = channel; params.mode = NULL; FINISH_FILTER; return; } } // GetKey? ////////// filter = ciFindGetKeyFilter(chat, channel); if(filter) { ciCallbackGetGlobalKeysParams params; params.success = CHATFalse; params.user = NULL; params.num = 0; params.keys = NULL; params.values = NULL; FINISH_FILTER; return; } } void ciErrTooManyChannelsHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrTooManyChannels called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Look for a matching filter. ////////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATTooManyChannels; params.channel = channel; FINISH_FILTER; } } void ciErrChannelIsFullHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrChannelIsFull called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Look for a matching filter. ////////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATChannelIsFull; params.channel = channel; FINISH_FILTER; } } void ciErrInviteOnlyChanHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrInviteOnlyChan called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Look for a matching filter. ////////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATInviteOnlyChannel; params.channel = channel; FINISH_FILTER; } } void ciErrBannedFromChanHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrBannedFromChan called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Look for a matching filter. ////////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATBannedFromChannel; params.channel = channel; FINISH_FILTER; } } void ciErrBadChannelKeyHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrBadChannelKey called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Look for a matching filter. ////////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATBadChannelPassword; params.channel = channel; FINISH_FILTER; } } void ciErrBadChanMaskHandler(CHAT chat, const ciServerMessage * message) { ciFilterMatch match; ciServerMessageFilter * filter; char * channel; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrBadChanMask called\n"); #endif assert(message->numParams == 3); if(message->numParams != 3) return; //ERRCON // Get the channel. /////////////////// channel = message->params[1]; // Look for a matching filter. ////////////////////////////// memset(&match, 0, sizeof(ciFilterMatch)); match.type = TYPE_JOIN; match.name = channel; filter = ciFindFilter(chat, 1, &match); if(filter != NULL) { ciCallbackEnterChannelParams params; params.success = CHATFalse; params.result = CHATBadChannelMask; params.channel = channel; FINISH_FILTER; } } void ciErrNoSuchNickHandler(CHAT chat, const ciServerMessage * message) { #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrNoSuchNickHandler called\n"); #endif GSI_UNUSED(chat); GSI_UNUSED(message); } void ciErrErroneusNicknameHandler(CHAT chat, const ciServerMessage * message) { CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrErroneusNicknameHandler called\n"); #endif // Are we connecting? ///////////////////// if(connection->connecting) ciNickError(chat, CHAT_INVALID, connection->nick, 0, NULL); GSI_UNUSED(message); } void ciErrLoginFailedHandler(CHAT chat, const ciServerMessage * message) { CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrLoginFailedHandler called\n"); #endif // Are we connecting? ///////////////////// if(connection->connecting) { // No longer connecting. //////////////////////// connection->connecting = CHATFalse; // Call the connect failed callback. //////////////////////////////////// if(connection->connectCallback != NULL) connection->connectCallback(chat, CHATFalse, CHAT_LOGIN_FAILED, connection->connectParam); } GSI_UNUSED(message); } void ciErrNoUniqueNickHandler(CHAT chat, const ciServerMessage * message) { CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrNoUniqueNickHandler called\n"); #endif // Are we connecting? ///////////////////// if(connection->connecting) ciNickError(chat, CHAT_NO_UNIQUENICK, "", 0, NULL); GSI_UNUSED(message); } void ciErrUniqueNickExpiredHandler(CHAT chat, const ciServerMessage * message) { CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrUniqueNickExpiredHandler called\n"); #endif // Are we connecting? ///////////////////// if(connection->connecting) ciNickError(chat, CHAT_UNIQUENICK_EXPIRED, "", 0, NULL); GSI_UNUSED(message); } void ciErrRegisterNickFailedHandler(CHAT chat, const ciServerMessage * message) { int num; char * nicks; char * nick; char ** nickArray; int i; CONNECTION; #ifdef FEEDBACK_HANDLERS OutputDebugString("ciErrRegisterNickFailedHandler called\n"); #endif assert(message->numParams == 4); if(message->numParams != 4) return; //ERRCON // Get the params we need. ////////////////////////// num = atoi(message->params[1]); nicks = message->params[2]; // Are we connecting? ///////////////////// if(!connection->connecting) return; // Allocate space for the nicks. //////////////////////////////// nickArray = (char **)gsimalloc(sizeof(char *) * num); if(!nickArray) return; // Parse out the suggested nicks. ///////////////////////////////// nick = strtok(nicks, "\\"); for(i = 0 ; (i < num) && nick ; i++) { nickArray[i] = goastrdup(nick); if(!nickArray[i]) break; nick = strtok(NULL, "\\"); } // Make sure our num is correct. //////////////////////////////// num = i; // Call the nick error callback. //////////////////////////////// ciNickError(chat, CHAT_INVALID_UNIQUENICK, connection->uniquenick, num, nickArray); // Free the memory. /////////////////// for(i = 0 ; i < num ; i++) gsifree(nickArray[i]); gsifree(nickArray); }