/* ** Command & Conquer Generals(tm) ** Copyright 2025 Electronic Arts Inc. ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ //////////////////////////////////////////////////////////////////////////////// // // // (c) 2001-2003 Electronic Arts Inc. // // // //////////////////////////////////////////////////////////////////////////////// // FILE: GameSpyChat.cpp ////////////////////////////////////////////////////// // GameSpy chat handlers // Author: Matthew D. Campbell, February 2002 #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine #include "GameClient/GameText.h" #include "GameClient/GadgetListBox.h" #include "GameClient/LanguageFilter.h" #include "GameNetwork/GameSpy.h" #include "GameNetwork/GameSpyChat.h" #include "Common/QuotedPrintable.h" typedef set::const_iterator AsciiSetIter; /** * handleSlashCommands looks for slash ccommands and handles them, * returning true if it found one, false otherwise. * /i,/ignore list ignored players * /i,/ignore +name1 -name2 ignore name1, stop ignoring name2 * /m,/me: shorthand for an action * /o,/on: find command to look up a user's location * /f,/find: find command to look up a user's location * /p,/page: page user(s) * /r,/reply: reply to last page * /raw: raw IRC command (only in debug & internal) * /oper: become an IRC op (only in debug & internal) * /quit: send the IRC quit command to exit WOL */ static Bool handleSlashCommands( UnicodeString message, Bool isAction, GameWindow *playerListbox ) { /* if (message.getCharAt(0) == L'/') { UnicodeString remainder = UnicodeString(message.str() + 1); UnicodeString token; switch (message.getCharAt(1)) { case L'i': case L'I': remainder.nextToken(&token); if (token.compareNoCase(L"i") == 0 || token.compareNoCase(L"ignore") == 0) { if (remainder.isEmpty()) { // List the people we're ignoring TheWOL->addText(TheGameText->fetch("WOL:BeginIgnoreList")); set *ignoreList = getIgnoreList(); if (ignoreList) { UnicodeString msg; UnicodeString uName; AsciiSetIter iter = ignoreList->begin(); while (iter != ignoreList->end()) { uName.translate(*iter); msg.format(TheGameText->fetch("WOL:IgnoredUser"), uName.str()); TheWOL->addText(msg); iter++; } } TheWOL->addText(TheGameText->fetch("WOL:EndIgnoreList")); } while ( remainder.nextToken(&token) ) { AsciiString name; int doIgnore = 0; if (token.getCharAt(0) == L'+') { // Ignore somebody token = UnicodeString(token.str() + 1); name.translate(token); doIgnore = 1; } else if (token.getCharAt(0) == L'-') { // Listen to someone again token = UnicodeString(token.str() + 1); name.translate(token); doIgnore = 0; } else { // Ignore somebody token = UnicodeString(token.str()); name.translate(token); doIgnore = 1; } IChat *ichat = TheWOL->getIChat(); User user; strncpy((char *)user.name, name.str(), 9); user.name[9] = 0; ichat->SetSquelch(&user, doIgnore); if (doIgnore) addIgnore(name); else removeIgnore(name); UnicodeString msg; UnicodeString uName; uName.translate(name); msg.format(TheGameText->fetch("WOL:IgnoredUser"), uName.str()); TheWOL->addText(msg); } return true; } break; case L'r': case L'R': remainder.nextToken(&token); #if defined _DEBUG || defined _INTERNAL if (token.compareNoCase(L"raw") == 0) { // Send raw IRC commands (Ascii only) AsciiString str; str.translate(remainder); str.concat('\n'); IChat *ichat = TheWOL->getIChat(); ichat->RequestRawMessage(str.str()); TheWOL->addText(remainder); return true; // show it anyway } #endif break; #if defined _DEBUG || defined _INTERNAL case L'k': case L'K': remainder.nextToken(&token); if (token.compareNoCase(L"kick") == 0) { while ( remainder.nextToken(&token) ) { AsciiString name; name.translate(token); IChat *ichat = TheWOL->getIChat(); User user; strncpy((char *)user.name, name.str(), 9); user.name[9] = 0; ichat->RequestUserKick(&user); } return true; } break; #endif case L'o': case L'O': remainder.nextToken(&token); if (token.compareNoCase(L"on") == 0 || token.compareNoCase(L"o") == 0) { remainder.nextToken(&token); AsciiString userName; userName.translate(token); User user; strncpy((char *)user.name, userName.str(), 10); user.name[9] = 0; if (user.name[0] == 0) { // didn't enter a name TheWOL->addText(message); } else { // Send find command IChat *ichat = TheWOL->getIChat(); ichat->RequestGlobalFind(&user); } return true; // show it anyway } #if defined _DEBUG || defined _INTERNAL else if (token.compareNoCase(L"oper") == 0) { // Send raw IRC oper command AsciiString str; str.translate(message); str.concat('\n'); IChat *ichat = TheWOL->getIChat(); ichat->RequestRawMessage(str.str()); TheWOL->addText(message); return true; // show it anyway } #endif break; case L'p': case L'P': remainder.nextToken(&token); if (token.compareNoCase(L"page") == 0 || token.compareNoCase(L"p") == 0) { remainder.nextToken(&token); AsciiString userName; userName.translate(token); User user; strncpy((char *)user.name, userName.str(), 10); user.name[9] = 0; remainder.trim(); if (user.name[0] == 0 || remainder.isEmpty()) { // didn't enter a name or message TheWOL->addText(message); } else { // Send page command IChat *ichat = TheWOL->getIChat(); ichat->RequestGlobalUnicodePage(&user, remainder.str()); } return true; // show it anyway } break; case L'q': case L'Q': remainder.nextToken(&token); if (token.compareNoCase(L"quit") == 0) { TheWOL->setState(WOLAPI_LOGIN); TheWOL->addCommand(WOLCOMMAND_LOGOUT); //TheWOL->setScreen(WOLAPI_MENU_WELCOME); return true; // show it anyway } break; #if defined _DEBUG || defined _INTERNAL case L'c': case L'C': remainder.nextToken(&token); if (token.compareNoCase(L"colortest") == 0) { addColorText(token, 0xDD, 0xE2, 0x0D, 0xff); addColorText(token, 0xFF, 0x19, 0x19, 0xff); addColorText(token, 0x2A, 0x74, 0xE2, 0xff); addColorText(token, 0x3E, 0xD1, 0x2E, 0xff); addColorText(token, 0xFF, 0xA0, 0x19, 0xff); addColorText(token, 0x32, 0xD7, 0xE6, 0xff); addColorText(token, 0x95, 0x28, 0xBD, 0xff); addColorText(token, 0xFF, 0x9A, 0xEB, 0xff); return true; // show it anyway } break; #endif // _DEBUG || defined _INTERNAL } } */ return false; } static handleUnicodeMessage( const char *nick, UnicodeString msg, Bool isPublic, Bool isAction ); Bool GameSpySendChat( UnicodeString message, Bool isAction, GameWindow *playerListbox ) { RoomType roomType = StagingRoom; if (TheGameSpyChat->getCurrentGroupRoomID()) roomType = GroupRoom; message.trim(); // Echo the user's input to the chat window if (!message.isEmpty()) { // Check for slash commands if (handleSlashCommands(message, isAction, playerListbox)) { return false; // already handled } if (!playerListbox) { // Public message if (isAction) { peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), ActionMessage); //if (roomType == StagingRoom) //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, true); } else { peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), NormalMessage); //if (roomType == StagingRoom) //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, false); } return false; } // Get the selections (is this a private message?) Int maxSel = GadgetListBoxGetListLength(playerListbox); Int *selections; GadgetListBoxGetSelected(playerListbox, (Int *)&selections); if (selections[0] == -1) { // Public message if (isAction) { peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), ActionMessage); //if (roomType == StagingRoom) //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, true); } else { peerMessageRoom(TheGameSpyChat->getPeer(), roomType, UnicodeStringToQuotedPrintable(message).str(), NormalMessage); //if (roomType == StagingRoom) //handleUnicodeMessage(TheGameSpyChat->getloginName().str(), message, true, false); } return false; } else { // Private message // Construct a list AsciiString names = AsciiString::TheEmptyString; AsciiString tmp = AsciiString::TheEmptyString; AsciiString aStr; // AsciiString buf for translating Unicode entries names.format("%s", TheGameSpyChat->getLoginName().str()); for (int i=0; igetLoginName())) { tmp.format(",%s", aStr.str()); names.concat(tmp); } } else { break; } } if (!names.isEmpty()) { if (isAction) { peerMessagePlayer(TheGameSpyChat->getPeer(), names.str(), UnicodeStringToQuotedPrintable(message).str(), ActionMessage); } else { peerMessagePlayer(TheGameSpyChat->getPeer(), names.str(), UnicodeStringToQuotedPrintable(message).str(), NormalMessage); } } return true; } } return false; } void RoomMessageCallback(PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param) { DEBUG_LOG(("RoomMessageCallback\n")); handleUnicodeMessage(nick, QuotedPrintableToUnicodeString(message), true, (messageType == ActionMessage)); } void PlayerMessageCallback(PEER peer, const char * nick, const char * message, MessageType messageType, void * param) { DEBUG_LOG(("PlayerMessageCallback\n")); handleUnicodeMessage(nick, QuotedPrintableToUnicodeString(message), false, (messageType == ActionMessage)); } static handleUnicodeMessage( const char *nick, UnicodeString msg, Bool isPublic, Bool isAction ) { GameSpyColors style; Bool isOwner = false; Int flags = 0; if (TheGameSpyChat->getCurrentGroupRoomID()) peerGetPlayerFlags(TheGameSpyChat->getPeer(), nick, GroupRoom, &flags); else peerGetPlayerFlags(TheGameSpyChat->getPeer(), nick, StagingRoom, &flags); isOwner = flags & PEER_FLAG_OP; if (isPublic && isAction) { style = (isOwner)?GSCOLOR_CHAT_OWNER_EMOTE:GSCOLOR_CHAT_EMOTE; } else if (isPublic) { style = (isOwner)?GSCOLOR_CHAT_OWNER:GSCOLOR_CHAT_NORMAL; } else if (isAction) { style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER_EMOTE:GSCOLOR_CHAT_PRIVATE_EMOTE; } else { style = (isOwner)?GSCOLOR_CHAT_PRIVATE_OWNER:GSCOLOR_CHAT_PRIVATE; } UnicodeString name; name.translate(nick); // filters language // if( TheGlobalData->m_languageFilterPref ) // { TheLanguageFilter->filterLine(msg); // } UnicodeString fullMsg; if (isAction) { fullMsg.format( L"%ls %ls", name.str(), msg.str() ); } else { fullMsg.format( L"[%ls] %ls", name.str(), msg.str() ); } GameSpyAddText(fullMsg, style); } void GameSpyAddText( UnicodeString message, GameSpyColors color ) { GameWindow *textWindow = NULL; if (!textWindow) textWindow = listboxLobbyChat; if (!textWindow) textWindow = listboxGameSetupChat; if (!textWindow) return; GadgetListBoxAddEntryText(textWindow, message, GameSpyColor[color], -1, -1); }