/* ** Command & Conquer Renegade(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 . */ /****************************************************************************** * * NAME * $Archive: /Commando/Code/WWOnline/WOLSession.cpp $ * * DESCRIPTION * WOLSession is the entryway to Westwood Online. An object of this type * must exist in order to do anything WOL related. There should only be one * instance of this; retrieve it via GetInstance. * * PROGRAMMER * Steve Clinard & Denzil E. Long, Jr. * $Author: Steve_t $ * * VERSION INFO * $Revision: 79 $ * $Modtime: 2/08/02 11:31a $ * ******************************************************************************/ #include #include "WOLSession.h" #include "WOLChatObserver.h" #include "WOLNetUtilObserver.h" #include "WOLProduct.h" #include "WOLConnect.h" #include "WOLServer.h" #include "WaitCondition.h" #include "WOLErrorUtil.h" #include #include #ifdef _MSC_VER #pragma warning (push,3) #endif #include "systimer.h" #ifdef _MSC_VER #pragma warning (pop) #endif namespace WWOnline { RefPtr Session::_mInstance; /****************************************************************************** * * NAME * Session::GetInstance * * DESCRIPTION * Retrieve instance to Westwood Online session * * INPUTS * Create - True if session should be created. * * RESULT * Session - Session instance * ******************************************************************************/ RefPtr Session::GetInstance(bool okToCreate) { if (okToCreate && !_mInstance.IsValid()) { _mInstance = new Session; if (_mInstance->FinalizeCreate() == false) { _mInstance.Release(); } } return _mInstance; } /****************************************************************************** * * NAME * Session::Session * * DESCRIPTION * Default constructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ Session::Session() : mChatCookie(0), mNetUtilCookie(0), mCurrentConnectionStatus(ConnectionDisconnected), mAutoRequestFlags(0), mLadderPending(0), mPingsPending(0), mPingEnable(1), mLastUserDataRequestTime(0), mRequestedChannelType(-1), mRequestingServerList(false), mIgnoreServerLists(false), mIsInsider(false), mServerTime(0) { WWDEBUG_SAY(("WOL: Session instantiated\n")); // Initailize COM HRESULT hr = CoInitialize(NULL); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: CoInitialize() failed!\n")); } WWASSERT(SUCCEEDED(hr) && "CoInitialize() failed!"); } /****************************************************************************** * * NAME * Session::FinalizeCreate * * DESCRIPTION * Finalize session creation * * INPUTS * NONE * * RESULT * Success - True if successful. * ******************************************************************************/ bool Session::FinalizeCreate(void) { WWDEBUG_SAY(("WOL: Session Create\n")); Reset(); //--------------------------------------------------------------------------- // Create chat object //--------------------------------------------------------------------------- WWDEBUG_SAY(("WOL: Creating IID_IChat object\n")); WOL::IChat* chatObject = NULL; HRESULT hr = CoCreateInstance(WOL::CLSID_Chat, NULL, CLSCTX_INPROC_SERVER, WOL::IID_IChat, (void**)&chatObject); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: Failed to create IID_IChat\n")); return false; } if (chatObject) { mChat = chatObject; // Create chat events observer WWDEBUG_SAY(("WOL: Creating chat events observer\n")); CComPtr chatEvents; chatEvents.Attach(new ChatObserver); if (chatEvents == NULL) { WWDEBUG_SAY(("WOLERROR: Failed to create IChatEvents observer\n")); return false; } chatEvents->Init(*this); hr = mChat.Advise(chatEvents, WOL::IID_IChatEvent, &mChatCookie); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: Failed to advise IChatEvents observer\n")); return false; } mChatEvents = chatEvents; } //--------------------------------------------------------------------------- // Create netutil object //--------------------------------------------------------------------------- WWDEBUG_SAY(("WOL: Creating IID_INetUtil object\n")); WOL::INetUtil* utilObject = NULL; hr = CoCreateInstance(WOL::CLSID_NetUtil, NULL, CLSCTX_INPROC_SERVER, WOL::IID_INetUtil, (void **)&utilObject); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: Failed to create IID_INetUtil\n")); return false; } if (utilObject) { mNetUtil = utilObject; // Create net utility events observer WWDEBUG_SAY(("WOL: Creating netutil events observer\n")); CComPtr utilEvents; utilEvents.Attach(new NetUtilObserver); if (utilEvents == NULL) { WWDEBUG_SAY(("WOLERROR: Failed to create INetUtilEvents observer\n")); return false; } utilEvents->Init(*this); hr = mNetUtil.Advise(utilEvents, WOL::IID_INetUtilEvent, &mNetUtilCookie); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: Failed to advise INetUtilEvents observer\n")); return false; } mNetUtilEvents = utilEvents; } //--------------------------------------------------------------------------- // Setup for current product //--------------------------------------------------------------------------- WWDEBUG_SAY(("WOL: Setting product SKU\n")); RefPtrConst product = Product::Current(); if (!product.IsValid()) { WWDEBUG_SAY(("WOLERROR: WOLProduct not initialized\n")); return false; } const char* regPath = product->GetRegistryPath(); hr = mChat->SetAttributeValue("RegPath", regPath); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: SetAttributeValue(RegPath) HRESULT = %s\n", GetChatErrorString(hr))); return false; } unsigned int sku = product->GetSKU(); hr = mChat->SetProductSKU(sku); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: SetProductSKU() HRESULT = %s\n", GetChatErrorString(hr))); return false; } // Enable OnChannelTopic() to be called after OnChannelJoin() hr = mChat->SetAttributeValue("AutoTopic", "true"); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: SetAttributeValue(AutoTopic) HRESULT = %s\n", GetChatErrorString(hr))); return false; } mPingRequests.reserve(8); mUsers.reserve(32); return true; } /****************************************************************************** * * NAME * Session::~Session * * DESCRIPTION * Destructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ Session::~Session() { WWDEBUG_SAY(("WOL: Session destructing\n")); Reset(); if (mIGRObject) { WWDEBUG_SAY(("WOL: Releasing IID_IIGROptions object\n")); mIGRObject.Release(); } if (mNetUtil) { WWDEBUG_SAY(("WOL: Releasing IID_INetUtil object\n")); AtlUnadvise(mNetUtil, WOL::IID_INetUtilEvent, mNetUtilCookie); mNetUtil.Release(); } if (mChat) { WWDEBUG_SAY(("WOL: Releasing IID_IChat object\n")); AtlUnadvise(mChat, WOL::IID_IChatEvent, mChatCookie); mChat.Release(); } CoUninitialize(); } /****************************************************************************** * * NAME * Session::ReleaseReference * * DESCRIPTION * Release reference count * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::ReleaseReference(void) { RefCounted::ReleaseReference(); // If there is only the singleton reference then release the object. if (ReferenceCount() == 1) { _mInstance.Release(); } } /****************************************************************************** * * NAME * Session::Reset * * DESCRIPTION * Reset the WWOnline session * * INPUTS * * RESULT * NONE * ******************************************************************************/ void Session::Reset(void) { ClearServers(); SquadData::Reset(); mChatChannels.clear(); mGameChannels.clear(); mPatchFiles.clear(); mUsers.clear(); mBuddies.clear(); mLocatePendingUsers.clear(); mLocatingUser.Release(); } /****************************************************************************** * * NAME * Session::Process * * DESCRIPTION * Perform periodic processing * * INPUTS * NONE * * RESULT * ******************************************************************************/ bool Session::Process(void) { if (mCurrentConnectionStatus == ConnectionConnected) { MakeLocateUserRequests(); } DWORD theTime = TIMEGETTIME(); if (theTime < mLastUserDataRequestTime) { mLastUserDataRequestTime = theTime; } if (theTime >= (mLastUserDataRequestTime + 1000)) { mLastUserDataRequestTime = theTime; MakeSquadRequests(); MakeLocaleRequests(); MakeTeamRequests(); MakeLadderRequests(); } MakePingRequests(); mChat->PumpMessages(); mNetUtil->PumpMessages(); return false; } /****************************************************************************** * * NAME * Session::GetNewServerList * * DESCRIPTION * Get a new server list. * * INPUTS * NONE * * RESULT * Wait - Wait condition to process for serverlist. * ******************************************************************************/ RefPtr Session::GetNewServerList(void) { return ServerListWait::Create(this); } /****************************************************************************** * * NAME * Session::RequestServerList * * DESCRIPTION * Submit a request for server list. * * INPUTS * NONE * * RESULT * Success - True if request successful. * ******************************************************************************/ bool Session::RequestServerList(bool ignore) { RefPtrConst product(Product::Current()); if (!product.IsValid()) { WWASSERT(product.IsValid() && "WOLERROR: Product not initialized."); return false; } mIgnoreServerLists = ignore; mRequestingServerList = !ignore; unsigned int sku = product->GetLanguageSKU(); unsigned int version = product->GetVersion(); HRESULT hr = mChat->RequestServerList(sku, version, "NoUser", "NoPass", 30000); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestServerList() HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::LoginServer * * DESCRIPTION * Log user onto server. * * INPUTS * Server - Server to logon to. * Login - Login information * * RESULT * Wait - Wait condition to process for logging in. * ******************************************************************************/ RefPtr Session::LoginServer(const RefPtr& server, const RefPtr& login) { if (server.IsValid()) { WWDEBUG_SAY(("WOL: LoginServer connecting to '%s'\n", server->GetName())); } else { WWDEBUG_SAY(("WOL: LoginServer disconnecting\n")); } //--------------------------------------------------------------------------- // If this is the current server, check state of connection //--------------------------------------------------------------------------- if (mCurrentServer == server) { if (server.IsValid()) { // If already connected to this server, just return with success. // If connecting then wait for connection to finish. if (ConnectionConnected == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer already connected.\n")); RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CONNECTING")); wait->EndWait(WaitCondition::ConditionMet, WOLSTRING("WOL_CONNECTED")); return wait; } else if (ConnectionConnecting == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer already connecting.\n")); return EventValueWait::CreateAndObserve(*this, ConnectionConnected, WOLSTRING("WOL_CONNECTING")); } } else { // If already disconnected then just return with success. If disconnecting // then wait for disconnect to finish. if (ConnectionDisconnected == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer already disconnected.\n")); RefPtr wait = SingleWait::Create(WOLSTRING("WOL_DISCONNECTING")); wait->EndWait(WaitCondition::ConditionMet, WOLSTRING("WOL_DISCONNECTED")); return wait; } else if (ConnectionDisconnecting == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer already disconnecting.\n")); return EventValueWait::CreateAndObserve(*this, ConnectionDisconnected, WOLSTRING("WOL_DISCONNECTING")); } } } // Clean up on server switch or disconnect if (ConnectionConnected == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer disconnect cleanup.\n")); mCurrentChannelStatus = ChannelLeft; ChannelEvent chanEvent(mCurrentChannelStatus, mCurrentChannel); NotifyObservers(chanEvent); mCurrentChannel.Release(); mPendingChannel.Release(); mChatChannels.clear(); ChannelListEvent chatListEvent(ChannelListEvent::NewList, mChatChannels, 0); NotifyObservers(chatListEvent); RefPtrConst product = Product::Current(); WWASSERT(product.IsValid()); mGameChannels.clear(); ChannelListEvent gameListEvent(ChannelListEvent::NewList, mGameChannels, product->GetGameCode()); NotifyObservers(gameListEvent); } //--------------------------------------------------------------------------- // Process change of server connection //--------------------------------------------------------------------------- RefPtr serverWait = SerialWait::Create(); // If connecting or disconnecting, let that finish if (ConnectionDisconnecting == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer wait for disconnect to finish.\n")); RefPtr< EventValueWait > finish = EventValueWait::CreateAndObserve(*this, ConnectionDisconnected, WOLSTRING("WOL_DISCONNECTING")); serverWait->Add(finish); } else if (ConnectionConnecting == mCurrentConnectionStatus) { WWDEBUG_SAY(("WOL: LoginServer wait for connect to finish.\n")); RefPtr< EventValueWait > finish = EventValueWait::CreateAndObserve(*this, ConnectionConnected, WOLSTRING("WOL_DISCONNECTING")); serverWait->Add(finish); } // If connected or connecting to another server then disconnect from that server // before connecting to the new one. if (mCurrentServer.IsValid() || (mPendingServer.IsValid() && (mPendingServer != server))) { WWDEBUG_SAY(("WOL: LoginServer changing servers.\n")); if ((ConnectionConnected == mCurrentConnectionStatus) || (ConnectionConnecting == mCurrentConnectionStatus)) { WWDEBUG_SAY(("WOL: LoginServer disconnect from current server.\n")); RefPtr disconnect = DisconnectWait::Create(this); serverWait->Add(disconnect); } } mPendingServer = server; mPendingLogin = login; // Server == NULL is just a logout if (!server.IsValid()) { return serverWait; } if (!login.IsValid()) { WWASSERT(login.IsValid()); return serverWait; } // Finally, connect to desired server. Request to connect is embedded in Wait_Beginning WWDEBUG_SAY(("WOL: LoginServer connect to new server.\n")); RefPtr connect = ConnectWait::Create(this, server, login); serverWait->Add(connect); return serverWait; } /****************************************************************************** * * NAME * Session::Logout * * DESCRIPTION * Log current user off. * * INPUTS * NONE * * RESULT * Wait - Wait condition to process for logout. * ******************************************************************************/ RefPtr Session::Logout(void) { WWDEBUG_SAY(("WOL: Logout\n")); return LoginServer(RefPtr(), RefPtr()); } /****************************************************************************** * * NAME * Session::ClearServers * * DESCRIPTION * Clear internal server lists * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::ClearServers(void) { mRequestingServerList = false; mIgnoreServerLists = false; mIRCServers.clear(); mLadderServer.Release(); mGameResultsServer.Release(); mWDTServer.Release(); mMGLServers.clear(); mPingServers.clear(); } /****************************************************************************** * * NAME * Session::EnableProgressiveChannelList * * DESCRIPTION * Enable / Disable the receipt of progressive channel lists. * * INPUTS * Enable - True to enable; False to disable. * * RESULT * Success - True if operation is successful. * ******************************************************************************/ bool Session::EnableProgressiveChannelList(bool enable) { const char* onoff = ((enable == true) ? "true" : "false"); HRESULT hr = mChat->SetAttributeValue("IncrementalChannelLists", onoff); return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::RequestChannelList * * DESCRIPTION * * INPUTS * Type - Channel type to request. * AutoPing - * * RESULT * Success - True if request successful. * ******************************************************************************/ bool Session::RequestChannelList(int channelType, bool autoPing) { WWDEBUG_SAY(("WOL: RequestChannelList %d\n", channelType)); if (mRequestedChannelType != -1) { WWDEBUG_SAY(("WOLERROR: RequestChannelList already pending\n")); return false; } HRESULT hr = mChat->RequestChannelList(channelType, autoPing); if (SUCCEEDED(hr)) { mRequestedChannelType = channelType; return true; } WWDEBUG_SAY(("WOLERROR: RequestChannelList() HRESULT = %s\n", GetChatErrorString(hr))); return false; } /****************************************************************************** * * NAME * Session::FindChannel * * DESCRIPTION * Find a channel by name. * * INPUTS * Name - Name of channel to look for. * * RESULT * Channel - * ******************************************************************************/ RefPtr Session::FindChannel(const wchar_t* channelName) { if (channelName == NULL) { return NULL; } if (mCurrentChannel.IsValid()) { const WideStringClass& name = mCurrentChannel->GetName(); if (name.Compare_No_Case(channelName) == 0) { return mCurrentChannel; } } RefPtr channel = FindChatChannel(channelName); if (!channel.IsValid()) { channel = FindGameChannel(channelName); } return channel; } RefPtr Session::FindChannel(const char* channelName) { if (channelName == NULL) { return NULL; } if (mCurrentChannel.IsValid()) { WOL::Channel& wolChannel = mCurrentChannel->GetData(); if (stricmp(channelName, (const char*)wolChannel.name) == 0) { return mCurrentChannel; } } RefPtr channel = FindChatChannel(channelName); if (!channel.IsValid()) { channel = FindGameChannel(channelName); } return channel; } /****************************************************************************** * * NAME * Session::JoinChannel * * DESCRIPTION * Join the specified channel. * * INPUTS * Channel - Channel to join. * * RESULT * Wait - Wait condition to process for joining channel * ******************************************************************************/ RefPtr Session::JoinChannel(const RefPtr& channel, const wchar_t* password) { // If we are not connected then we cannot join a channel. if (mCurrentConnectionStatus != ConnectionConnected) { WWASSERT(mCurrentConnectionStatus == ConnectionConnected); RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELJOIN")); wait->EndWait(WaitCondition::Error, WOLSTRING("WOL_NOTCONNECTED")); return wait; } // If we are already connected to the requested channel then done. if (mCurrentChannel == channel) { RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELJOIN")); wait->EndWait(WaitCondition::ConditionMet, WOLSTRING("WOL_CONNECTED")); return wait; } // Use default product password if one is not provided if (password == NULL) { RefPtrConst product = Product::Current(); WWASSERT(product.IsValid()); password = product->GetChannelPassword(); } // Set up wait condition for joining channel mPendingChannel = channel; RefPtr wait = SerialWait::Create(); if (wait.IsValid()) { // Leave current channel if (mCurrentChannel.IsValid()) { RefPtr leaveWait = LeaveChannelWait::Create(this); wait->Add(leaveWait); } // Join new channel if (channel.IsValid()) { RefPtr joinWait = JoinChannelWait::Create(this, channel, password); wait->Add(joinWait); } } return wait; } RefPtr Session::JoinChannel(const wchar_t* chanName, const wchar_t* password, int type) { // If we are not connected then we cannot join a channel. if (mCurrentConnectionStatus != ConnectionConnected) { WWASSERT(mCurrentConnectionStatus == ConnectionConnected); RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELJOIN")); wait->EndWait(WaitCondition::Error, WOLSTRING("WOL_NOTCONNECTED")); return wait; } // If we are already connected to the requested channel then done. if (mCurrentChannel.IsValid()) { const WideStringClass& curChanName = mCurrentChannel->GetName(); if (curChanName.Compare_No_Case(chanName) == 0) { RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELJOIN")); wait->EndWait(WaitCondition::ConditionMet, WOLSTRING("WOL_CONNECTED")); return wait; } } // Use default product password if one is not provided if (password == NULL) { RefPtrConst product = Product::Current(); WWASSERT(product.IsValid()); password = product->GetChannelPassword(); } // Set up wait condition for joining channel RefPtr wait = SerialWait::Create(); if (wait.IsValid()) { // Leave current channel if (mCurrentChannel.IsValid()) { RefPtr leaveWait = LeaveChannelWait::Create(this); wait->Add(leaveWait); } if (chanName) { // Join new channel RefPtr joinWait = JoinChannelWait::Create(this, chanName, password, type); wait->Add(joinWait); } } return wait; } /****************************************************************************** * * NAME * Session::RequestChannelJoin * * DESCRIPTION * * INPUTS * NONE * * RESULT * Success - True if request successful. * ******************************************************************************/ bool Session::RequestChannelJoin(const RefPtr& channel, const wchar_t* password) { if (channel.IsValid() && password) { WWDEBUG_SAY(("WOL: RequestChannelJoin C:%S P:%S\n", (const WCHAR*)channel->GetName(), password)); mPendingChannel = channel; WOL::Channel& wolChannel = channel->GetData(); wcstombs((char*)wolChannel.key, password, sizeof(wolChannel.key)); // If the channel is not in the channel list then mark it as hidden. RefPtr inList = FindChannel(channel->GetName()); wolChannel.hidden = (inList.IsValid() ? 0 : 1); HRESULT hr = mChat->RequestChannelJoin(&wolChannel); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestChannelJoin() HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } return false; } /****************************************************************************** * * NAME * Session::LeaveChannel * * DESCRIPTION * * INPUTS * NONE * * RESULT * Wait - Wait condition to process for leaving channel * ******************************************************************************/ RefPtr Session::LeaveChannel(void) { if (!mCurrentChannel.IsValid() || (ChannelJoined != mCurrentChannelStatus)) { mCurrentChannel.Release(); mCurrentChannelStatus = ChannelLeft; RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELLEAVE")); wait->EndWait(WaitCondition::ConditionMet, WOLSTRING("WOL_CHANNELLEFT")); return wait; } return LeaveChannelWait::Create(this); } bool Session::RequestLeaveChannel(void) { if (ChannelJoined == mCurrentChannelStatus) { HRESULT hr = mChat->RequestChannelLeave(); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestChannelLeave() failed HRESULT = %s\n", GetChatErrorString(hr))); return false; } mCurrentChannelStatus = ChannelLeaving; } return true; } /****************************************************************************** * * NAME * Session::GetNewChatChannelList * * DESCRIPTION * Request a new chat channel list. * * INPUTS * NONE * * RESULT * Wait - Wait condition to process for chat channel list. * ******************************************************************************/ RefPtr Session::GetNewChatChannelList(void) { return ChannelListWait::Create(this, 0); } /****************************************************************************** * * NAME * Session::FindChatChannel * * DESCRIPTION * Find a chat channel. * * INPUTS * ChannelName - Name of channel to search for. * * RESULT * Channel - * ******************************************************************************/ RefPtr Session::FindChatChannel(const wchar_t* channelName) { return FindChannelInList(mChatChannels, channelName); } RefPtr Session::FindChatChannel(const char* channelName) { return FindChannelInList(mChatChannels, channelName); } /****************************************************************************** * * NAME * Session::GetNewGameChannelList * * DESCRIPTION * Get new game channel list. * * INPUTS * NONE * * RESULT * Wait - Wait condition to process for obtaining new channel list. * ******************************************************************************/ RefPtr Session::GetNewGameChannelList(void) { RefPtrConst product = Product::Current(); if (product.IsValid()) { int channelType = product->GetGameCode(); return ChannelListWait::Create(this, channelType); } return NULL; } /****************************************************************************** * * NAME * Session::RequestGameChannelList * * DESCRIPTION * Submit request for game channel list. * * INPUTS * NONE * * RESULT * Success - True if request successful. * ******************************************************************************/ bool Session::RequestGameChannelList(void) { RefPtrConst product = Product::Current(); if (!product.IsValid()) { WWASSERT(product.IsValid()); return false; } int channelType = product->GetGameCode(); return RequestChannelList(channelType, false); } /****************************************************************************** * * NAME * Session::FindGameChannel * * DESCRIPTION * Find a game channel. * * INPUTS * ChannelName - Name of channel to search for. * * RESULT * Channel - * ******************************************************************************/ RefPtr Session::FindGameChannel(const wchar_t* channelName) { return FindChannelInList(mGameChannels, channelName); } RefPtr Session::FindGameChannel(const char* channelName) { return FindChannelInList(mGameChannels, channelName); } /****************************************************************************** * * NAME * Session::CreateChannel * * DESCRIPTION * Create a new channel. * * INPUTS * Name - Name of new channel. * Password - Password for channel. * * RESULT * Wait - Wait condition to process for channel creation. * ******************************************************************************/ RefPtr Session::CreateChannel(const wchar_t* name, const wchar_t* password, int type) { WWDEBUG_SAY(("WOL: CreateChannel '%S' Type %ld\n", name, type)); if (mCurrentConnectionStatus != ConnectionConnected) { WWASSERT(mCurrentConnectionStatus == ConnectionConnected); RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELCREATE")); wait->EndWait(WaitCondition::Error, WOLSTRING("WOL_NOTCONNECTED")); return wait; } // If we are already connected to the requested channel then done. if (mCurrentChannel.IsValid()) { const WideStringClass& curChanName = mCurrentChannel->GetName(); if (curChanName.Compare_No_Case(name) == 0) { RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELCREATE")); wait->EndWait(WaitCondition::Error, WOLSTRING("WOL_CONNECTED")); return wait; } } RefPtr channel = ChannelData::Create(name, password, type); // Set up wait condition for creating channel mPendingChannel = channel; RefPtr wait = SerialWait::Create(); // Leave current channel if (mCurrentChannel.IsValid()) { RefPtr leave = LeaveChannelWait::Create(this); wait->Add(leave); } // Create & Join channel RefPtr create = CreateChannelWait::Create(this, channel, password); wait->Add(create); return wait; } /****************************************************************************** * * NAME * Session::CreateChannel * * DESCRIPTION * Create a new channel * * INPUTS * Channel - Channel data to create from. * Password - Password for joining channel * * RESULT * Wait - Wait condition to process for creating channel * ******************************************************************************/ RefPtr Session::CreateChannel(const RefPtr& channel, const wchar_t* password) { WWASSERT(channel.IsValid()); WWDEBUG_SAY(("WOL: CreateChannel '%S'\n", (const WCHAR*)channel->GetName())); if (mCurrentConnectionStatus != ConnectionConnected) { WWASSERT(mCurrentConnectionStatus == ConnectionConnected); RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELCREATE")); wait->EndWait(WaitCondition::Error, WOLSTRING("WOL_NOTCONNECTED")); return wait; } // If we are already connected to the requested channel then done. if (mCurrentChannel.IsValid()) { const WideStringClass& curChanName = mCurrentChannel->GetName(); if (curChanName.Compare_No_Case(channel->GetName()) == 0) { RefPtr wait = SingleWait::Create(WOLSTRING("WOL_CHANNELCREATE")); wait->EndWait(WaitCondition::Error, WOLSTRING("WOL_CONNECTED")); return wait; } } mPendingChannel = channel; // Set up wait condition for creating channel RefPtr wait = SerialWait::Create(); // Leave current channel if (mCurrentChannel.IsValid()) { RefPtr leave = LeaveChannelWait::Create(this); wait->Add(leave); } // Create & join channel RefPtr create = CreateChannelWait::Create(this, channel, password); wait->Add(create); return wait; } /****************************************************************************** * * NAME * Session::GetChannelTopic * * DESCRIPTION * Get the topic of the current channel * * INPUTS * NONE * * RESULT * Topic - Channel topic or NULL if no topic or not in channel. * ******************************************************************************/ const char* Session::GetChannelTopic(void) const { const RefPtr& channel = GetCurrentChannel(); if (channel.IsValid()) { return channel->GetTopic(); } return NULL; } /****************************************************************************** * * NAME * Session::SendChannelTopic * * DESCRIPTION * Send the topic of the current channel. * * INPUTS * NONE * * RESULT * True if request successful. * ******************************************************************************/ bool Session::SendChannelTopic(void) { const RefPtr& channel = GetCurrentChannel(); if (channel.IsValid()) { const char* topic = channel->GetTopic(); if (topic) { HRESULT hr = mChat->RequestChannelTopic(topic); if (SUCCEEDED(hr)) { return true; } WWDEBUG_SAY(("WOLERROR: SendChannelTopic() HRESULT = %s\n", GetChatErrorString(hr))); } } return false; } /****************************************************************************** * * NAME * Session::SendChannelExtraInfo * * DESCRIPTION * Send the extra info for the current channel. * * INPUTS * NONE * * RESULT * True if request successful. * ******************************************************************************/ bool Session::SendChannelExtraInfo(void) { const RefPtr& channel = GetCurrentChannel(); if (channel.IsValid()) { const char* exInfo = channel->GetExtraInfo(); if (exInfo) { HRESULT hr = mChat->SetChannelExInfo(exInfo); if (SUCCEEDED(hr)) { return true; } WWDEBUG_SAY(("WOLERROR: ChangeChannelExtraInfo() HRESULT = %s\n", GetChatErrorString(hr))); } } return false; } /****************************************************************************** * * NAME * Session::RequestUserList * * DESCRIPTION * Request a new user list for the current channel from the IRC server. * * INPUTS * NONE * * RESULT * Success - True if request successful. * ******************************************************************************/ bool Session::RequestUserList(void) { HRESULT hr = mChat->RequestUserList(); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestUserList() HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::FindUser * * DESCRIPTION * Search for a user in the user list by name. * * INPUTS * Nickname - Name of user to look for. * * RESULT * User - User, if found. * ******************************************************************************/ RefPtr Session::FindUser(const wchar_t* nickname) { // Check the current user first. if (mCurrentUser.IsValid()) { const WideStringClass& username = mCurrentUser->GetName(); if (username.Compare_No_Case(nickname) == 0) { return mCurrentUser; } } // Check in channels user list return FindUserInList(nickname, mUsers); } /****************************************************************************** * * NAME * Session::GetUserOrBuddy * * DESCRIPTION * Search for a user in the user list by name. * * INPUTS * Nickname - Name of user to look for. * * RESULT * User - User, if found. * ******************************************************************************/ RefPtr Session::GetUserOrBuddy(const wchar_t* name) { RefPtr user = FindUser(name); if (!user.IsValid()) { user = FindBuddy(name); } return user; } /****************************************************************************** * * NAME * Session::IsCurrentUser * * DESCRIPTION * Check if the specified user is the one logged in. * * INPUTS * User - User to check. * * RESULT * True if specified user is the current one. * ******************************************************************************/ bool Session::IsCurrentUser(const RefPtr& user) const { return user.IsValid() && mCurrentUser.IsValid() && user->GetName() == mCurrentUser->GetName(); } bool Session::IsCurrentUser(const wchar_t* username) const { if (username && mCurrentUser.IsValid()) { const WideStringClass& name = mCurrentUser->GetName(); return (name.Compare_No_Case(username) == 0); } return false; } /****************************************************************************** * * NAME * Session::ChangeCurrentUserLocale * * DESCRIPTION * Change the locale for the user currently logged in. * * INPUTS * Locale - New locale * * RESULT * True if successful. * ******************************************************************************/ bool Session::ChangeCurrentUserLocale(WOL::Locale locale) { if (mCurrentUser.IsValid() && (mCurrentUser->GetLocale() != locale)) { HRESULT hr = mChat->RequestSetLocale(locale); if (SUCCEEDED(hr)) { return true; } WWDEBUG_SAY(("WOLERROR: RequestSetLocale() HRESULT = %s\n", GetChatErrorString(hr))); } return false; } /****************************************************************************** * * NAME * Session::SquelchUser * * DESCRIPTION * Enable / disable squelching (ignoring) of other users. * * INPUTS * User - User to squelch / unsquelch * OnOff - True to squelch; False unsquelch * * RESULT * True if operation successful. * ******************************************************************************/ bool Session::SquelchUser(const RefPtr& user, bool onoff) { if (user.IsValid()) { WWDEBUG_SAY(("WOL: SquelchUser '%S'\n", user->GetName())); HRESULT hr = mChat->SetSquelch(&user->GetData(), onoff); if (SUCCEEDED(hr)) { user->Squelch(onoff); return true; } WWDEBUG_SAY(("WOLERROR: SetSquelch() HRESULT = %s\n", GetChatErrorString(hr))); } return false; } /****************************************************************************** * * NAME * Session::KickUser * * DESCRIPTION * Make a request to kick a user from the current channel. Kicking is only * allowed for channel owners. * * INPUTS * User - Name of user to kick from the channel * * RESULT * True if operation successful. * ******************************************************************************/ bool Session::KickUser(const wchar_t* username) { if (username) { RefPtr user = FindUserInList(username, mUsers); if (user.IsValid()) { WWDEBUG_SAY(("WOL: KickUser '%S'\n", user->GetName())); HRESULT hr = mChat->RequestUserKick(&user->GetData()); if (SUCCEEDED(hr)) { return true; } WWDEBUG_SAY(("WOLERROR: RequestUserKick() HRESULT = %s\n", GetChatErrorString(hr))); } } return false; } /****************************************************************************** * * NAME * Session::BanUser * * DESCRIPTION * Make a request to ban / unban a user from the current channel. * Banning is only allowed for channel owners. * * INPUTS * User - Name of user to ban / unban from the channel * Ban - True to ban; False to remove ban * * RESULT * True if operation successful. * ******************************************************************************/ bool Session::BanUser(const wchar_t* username, bool banned) { if (username) { WWDEBUG_SAY(("WOL: BanUser '%S'\n", username)); char ansiName[64]; wcstombs(ansiName, username, sizeof(ansiName)); HRESULT hr = mChat->RequestChannelBan(ansiName, banned); if (SUCCEEDED(hr)) { return true; } WWDEBUG_SAY(("WOLERROR: RequestChannelBan() HRESULT = %s\n", GetChatErrorString(hr))); } return false; } /****************************************************************************** * * NAME * Session::PageUser * * DESCRIPTION * Send page message to the specified user. * * INPUTS * User - User to page. * Message - Message to send. * * RESULT * True if operation successful. * ******************************************************************************/ bool Session::PageUser(const wchar_t* username, const wchar_t* message) { if ((username && wcslen(username)) && (message && wcslen(message))) { WOL::User wolUser; memset((void*)&wolUser, 0, sizeof(wolUser)); wcstombs((char*)&wolUser.name, username, sizeof(wolUser.name)); wolUser.name[sizeof(wolUser.name) - 1] = 0; if (IsAnsiText(message)) { char ansiMessage[1024]; wcstombs(ansiMessage, message, sizeof(ansiMessage)); HRESULT hr = mChat->RequestPage(&wolUser, ansiMessage); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestPage() HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } else { HRESULT hr = mChat->RequestUnicodePage(&wolUser, message); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestUnicodePage() HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } } return false; } /****************************************************************************** * * NAME * Session::RequestLocateUser * * DESCRIPTION * Locate the user on Westwood Online. * * INPUTS * Name - Login name of the user to locate. * * RESULT * True if operation successful. * ******************************************************************************/ void Session::RequestLocateUser(const wchar_t* name) { if (name && wcslen(name)) { // If we already have the user then submit it, otherwise create a new user entry. RefPtr user = GetUserOrBuddy(name); if (!user.IsValid()) { user = UserData::Create(name); } RequestLocateUser(user); } } void Session::RequestLocateUser(const RefPtr& user) { if (user.IsValid()) { // If the user is already pending then do not add him again. RefPtr pending = FindUserInList(user->GetName(), mLocatePendingUsers); if (pending.IsValid()) { return; } // Is user currently being located then done if (mLocatingUser.IsValid()) { const WideStringClass& userName = user->GetName(); if (userName.Compare_No_Case(mLocatingUser->GetName()) == 0) { return; } } // Add the user to the pending locate list mLocatePendingUsers.push_back(user); } } /****************************************************************************** * * NAME * Session::MakeLocateUserRequests * * DESCRIPTION * Make a request to the server to locate users. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::MakeLocateUserRequests(void) { if (!mLocatePendingUsers.empty() && !mLocatingUser.IsValid()) { mLocatingUser = mLocatePendingUsers[0]; mLocatePendingUsers.erase(mLocatePendingUsers.begin()); HRESULT hr = mChat->RequestFind(&mLocatingUser->GetData()); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestFind() HRESULT = %s\n", GetChatErrorString(hr))); } } } /****************************************************************************** * * NAME * Session::RequestUserLocale * * DESCRIPTION * Make a request to query a users locale. (IE: US, Germany, Korea) * * INPUTS * Name - Name of user to query locale for. * * RESULT * NONE * ******************************************************************************/ void Session::RequestUserLocale(const wchar_t* username) { if (username && (wcslen(username) > 0)) { // Make sure the user is not already in the list. const unsigned int count = mLocaleRequests.size(); for (unsigned int index = 0; index < count; ++index) { if (mLocaleRequests[index].Compare_No_Case(username) == 0) { return; } } mLocaleRequests.push_back(username); } } /****************************************************************************** * * NAME * Session::MakeLocaleRequests * * DESCRIPTION * Make request to server to query user locales. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::MakeLocaleRequests(void) { if (!mLocaleRequests.empty()) { const unsigned int count = min(10, mLocaleRequests.size()); WOL::User* users = new WOL::User[count]; WWASSERT(users && "Failed to create temporary users array"); if (users) { for (unsigned int index = 0; index < count; ++index) { WideStringClass& username = mLocaleRequests[index]; WWDEBUG_SAY(("WOL: Requesting locale for '%S'\n", (const WCHAR*)username)); WOL::User& user = users[index]; wcstombs((char*)user.name, username, sizeof(user.name)); user.name[sizeof(user.name) - 1] = 0; if (index == (count - 1)) { user.next = NULL; } else { user.next = &users[index + 1]; } } HRESULT hr = mChat->RequestUserLocale(users); // If request was successful then remove from the pending list. if (SUCCEEDED(hr)) { LocaleRequestColl::iterator first = mLocaleRequests.begin(); mLocaleRequests.erase(first, first + count); } else { WWDEBUG_SAY(("WOLERROR: RequestUserLocale() HRESULT = %s\n", GetChatErrorString(hr))); } delete []users; } } } /****************************************************************************** * * NAME * Session::RequestSquadInfoByID * * DESCRIPTION * Request information about a squad by Squad ID. * * INPUTS * SquadID - Identifier of squad * * RESULT * NONE * ******************************************************************************/ void Session::RequestSquadInfoByID(unsigned long squadID) { if (squadID != 0) { // MAGICK NUMBER -- itoa handles up to 33 digit numbers wchar_t idString[34]; // MAGICK NUMBER - 10 - squadID is base 10. _itow(squadID, idString, 10); // Only add a request that is not already pending. const unsigned int count = mSquadRequests.size(); for (unsigned int index = 0; index < count; ++index) { if (mSquadRequests[index] == idString) { return; } } mSquadRequests.push_back(idString); } } /****************************************************************************** * * NAME * Session::RequestSquadInfoByMemberName * * DESCRIPTION * Request information about a squad by Member Name. * * INPUTS * memberName - user name of a member * * RESULT * NONE * ******************************************************************************/ void Session::RequestSquadInfoByMemberName(const wchar_t* memberName) { if (memberName && (wcslen(memberName) > 0)) { // Only add a request that is not already pending. for (unsigned int index = 0; index < mSquadRequests.size(); index++) { if (mSquadRequests[index].Compare_No_Case(memberName) == 0) { return; } } mSquadRequests.push_back(memberName); } } /****************************************************************************** * * NAME * Session::MakeSquadRequests * * DESCRIPTION * Make request to server to query squad information. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::MakeSquadRequests(void) { if (!mSquadRequests.empty() && mSquadPending.empty()) { // Send up to ten requests at a time. unsigned int count = min(10, mSquadRequests.size()); // Send each request in turn, for (unsigned int index = 0; index < count; ++index) { const WideStringClass& request = mSquadRequests[index]; HRESULT hr = E_FAIL; // Check to see if this is an ID or a name // - names can't have the first character be a number so this works. wchar_t firstChar = request[0]; if (iswdigit(firstChar)) { unsigned int squadID = _wtoi(request); WWDEBUG_SAY(("WOL: SquadInfo requested for ID %ld\n", squadID)); hr = mChat->RequestSquadInfo(squadID); } else { StringClass name(0, true); request.Convert_To(name); WWDEBUG_SAY(("WOL: SquadInfo requested for '%s'\n", (const char*)name)); hr = mChat->RequestSquadByName(name); } if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestSquadInfo() HRESULT = %s\n", GetChatErrorString(hr))); break; } mSquadPending.push_back(request); } SquadRequestColl::iterator first = mSquadRequests.begin(); mSquadRequests.erase(first, first + index); } } /****************************************************************************** * * NAME * Session::RequestTeamInfo * * DESCRIPTION * Make a request to query a users team information. * * INPUTS * Name - Name of user to request team information for. * * RESULT * NONE * ******************************************************************************/ void Session::RequestTeamInfo(const wchar_t* username) { if (username && (wcslen(username) > 0)) { for (unsigned int index = 0; index < mTeamRequests.size(); index++) { if (mTeamRequests[index].Compare_No_Case(username) == 0) { return; } } mTeamRequests.push_back(username); } } /****************************************************************************** * * NAME * Session::MakeTeamRequests * * DESCRIPTION * Send team requests to the server. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::MakeTeamRequests(void) { if (!mTeamRequests.empty()) { WWDEBUG_SAY(("WOL: Requesting team information\n")); unsigned int count = min(10, mTeamRequests.size()); WOL::User* users = new WOL::User[count]; WWASSERT(users && "Failed to create temporary users array"); if (users) { for (unsigned int index = 0; index < count; index++) { WOL::User& user = users[index]; WideStringClass& username = mTeamRequests[index]; wcstombs((char*)user.name, username.Peek_Buffer(), sizeof(user.name)); user.name[sizeof(user.name) - 1] = 0; if (index == count - 1) { user.next = NULL; } else { user.next = users + index + 1; } } HRESULT hr = mChat->RequestUserTeam(users); // If request was successful then remove from the pending list. if (SUCCEEDED(hr)) { TeamRequestColl::iterator first = mTeamRequests.begin(); mTeamRequests.erase(first, first + count); } else { WWDEBUG_SAY(("WOL: HRESULT = %s\n", GetChatErrorString(hr))); } delete []users; } } } /****************************************************************************** * * NAME * Session::RequestLadderInfo * * DESCRIPTION * Request a users ladder information. * * INPUTS * User - Name of user to request information for. * Type - Type of ladder requesting * * RESULT * NONE * ******************************************************************************/ void Session::RequestLadderInfo(const wchar_t* name, unsigned long type) { if (name && (wcslen(name) > 0) && (type & LADDERTYPE_MASK)) { WideStringClass request(64, true); request = L"itc:"; // Clan ladder requests are mutually exclusive to other ladder requests // because it requires the name of the clan, while the other requests use // the users login name. if (type & LadderType_Clan) { WWASSERT((type & (LadderType_Individual | LadderType_Team)) == 0); request[2] = L'C'; } else { if (type & LadderType_Individual) { request[0] = L'I'; } if (type & LadderType_Team) { request[1] = L'T'; } } // Append the name to the request request += name; // Check if the request is already in the list. LadderRequestList::iterator pending = mLadderRequests.begin(); while (pending != mLadderRequests.end()) { if (request.Compare_No_Case(*pending) == 0) { return; } pending++; } WWDEBUG_SAY(("WOL: LadderInfo request added '%S'.\n", request)); mLadderRequests.push_back(request); } } /****************************************************************************** * * NAME * Session::MakeLadderRequests * * DESCRIPTION * Send ladder requests to the server. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::MakeLadderRequests(void) { // If there are requests and nothing is pending then send the next request if (!mLadderRequests.empty() && mLadderPending == 0) { RefPtrConst product = Product::Current(); if (mLadderServer.IsValid() && product.IsValid()) { // Build a single key from up to 10 requests with the same request type. char keys[256]; keys[0] = 0; unsigned int count = 0; LadderRequestList::iterator request = mLadderRequests.begin(); const WideStringClass& firstRequest = *request; while ((count < 10) && (request != mLadderRequests.end())) { // Stop appending requests as soon as we encounter a different type. if (wcsncmp(firstRequest, *request, 3) != 0) { break; } // Seperate key entries with a colon if (count > 0) { strcat(keys, ":"); } // The request name follows the type WCHAR* widename = wcschr(*request, L':'); WWASSERT(widename != NULL && "Invalid Ladder Request"); widename++; // Add the request char name[64]; wcstombs(name, widename, 64); strcat(keys, name); // Next request count++; request++; } WWDEBUG_SAY(("WOL: LadderInfo requested for '%s'.\n", keys)); mLadderPending = count; const char* hostAddr = mLadderServer->GetHostAddress(); unsigned int port = mLadderServer->GetPort(); unsigned long sku = product->GetLadderSKU(); // Request individual ladder if (firstRequest[0] == L'I') { HRESULT hr = mNetUtil->RequestLadderList(hostAddr, port, keys, sku, -1, 0, 0); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestLadderList (Individual) HRESULT = %s\n", GetNetUtilErrorString(hr))); return; } mLadderPending |= LadderType_Individual; } // Request team ladder if (firstRequest[1] == L'T') { HRESULT hr = mNetUtil->RequestLadderList(hostAddr, port, keys, (sku | LadderType_Team), -1, 0, 0); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestLadderList (Team) HRESULT = %s\n", GetNetUtilErrorString(hr))); return; } mLadderPending |= LadderType_Team; } // Request clan ladder if (firstRequest[2] == L'C') { HRESULT hr = mNetUtil->RequestLadderList(hostAddr, port, keys, (sku | LadderType_Clan), -1, 0, 0); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestLadderList (Clan) HRESULT = %s\n", GetNetUtilErrorString(hr))); return; } mLadderPending |= LadderType_Clan; } } } } /****************************************************************************** * * NAME * Session::RequestUserDetails * * DESCRIPTION * Request detailed information about the user (Ladder, Clan, Team, etc...) * * INPUTS * User - User to request details for. * RequestFlags - Flags indicating the type of information to request. * * RESULT * NONE * ******************************************************************************/ void Session::RequestUserDetails(const RefPtr& user, unsigned long requestFlags) { if (user.IsValid()) { if (requestFlags & REQUEST_SQUADINFO) { // Request squad information for the user. unsigned int squadID = user->GetSquadID(); RefPtr squad = user->GetSquad(); bool requestSquad = (!squad.IsValid() && (squadID != 0)); bool changedSquad = (squad.IsValid() && (squadID != squad->GetID())); if (requestSquad || changedSquad) { // Look for the squad in the local cache squad = SquadData::FindByID(squadID); user->SetSquad(squad); // Request squad information if it is not in the local cache. if (!squad.IsValid()) { RequestSquadInfoByID(squadID); } else { UserEvent event(UserEvent::SquadInfo, user); NotifyObservers(event); } } } // Request locale information for this user. if ((requestFlags & REQUEST_LOCALE) && (user->GetLocale() == WOL::LOC_UNKNOWN)) { RequestUserLocale(user->GetName()); } // Request ladder information for this user. if ((requestFlags & REQUEST_LADDERINFO) && !user->GetLadder().IsValid()) { RequestLadderInfo(user->GetName(), LadderType_Team); } // Request team information for this user. if ((requestFlags & REQUEST_TEAMINFO) && (user->GetTeam() == 0)) { RequestTeamInfo(user->GetName()); } } } /****************************************************************************** * * NAME * Session::AutoRequestUserDetails * * DESCRIPTION * * INPUTS * * RESULT * NONE * ******************************************************************************/ void Session::AutoRequestUserDetails(const RefPtr& user) { RequestUserDetails(user, mAutoRequestFlags); } /****************************************************************************** * * NAME * Session::RequestBuddyList * * DESCRIPTION * Send a request to the server for our buddy list. * * INPUTS * NONE * * RESULT * Success - True if request successful * ******************************************************************************/ bool Session::RequestBuddyList(void) { HRESULT hr = mChat->RequestBuddyList(); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestBuddyList() failed HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::AddBuddy * * DESCRIPTION * Send a request to the server to add a buddy to our buddy list. * * INPUTS * Buddy - Name of buddy to add. * * RESULT * True if request sent successfully * ******************************************************************************/ bool Session::AddBuddy(const wchar_t* buddyName) { WOL::User wolUser; memset((void*)&wolUser, 0, sizeof(wolUser)); wcstombs((char*)&wolUser.name, buddyName, sizeof(wolUser.name)); wolUser.name[sizeof(wolUser.name) - 1] = 0; HRESULT hr = mChat->RequestBuddyAdd(&wolUser); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestBuddyAdd() failed HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::RemoveBuddy * * DESCRIPTION * Send a request to the server to remove a buddy from our buddy list. * * INPUTS * Buddy - Name of buddy to remove. * * RESULT * True if request sent successfully * ******************************************************************************/ bool Session::RemoveBuddy(const wchar_t* buddyName) { WOL::User wolUser; memset((void*)&wolUser, 0, sizeof(wolUser)); wcstombs((char*)&wolUser.name, buddyName, sizeof(wolUser.name)); wolUser.name[sizeof(wolUser.name) - 1] = 0; HRESULT hr = mChat->RequestBuddyDelete(&wolUser); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestBuddyDelete() failed HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::AllowFindPage * * DESCRIPTION * Set flags to allow / disallow user from being found or paged. * * INPUTS * AllowFind - True to allow user to be found; False to disallow. * AllowPage - True to allow user to be paged; False to disallow. * * RESULT * True if request successful * ******************************************************************************/ bool Session::AllowFindPage(bool allowFind, bool allowPage) { HRESULT hr = mChat->SetFindPage(allowFind, allowPage); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: SetFindPage() failed HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::SetBadLanguageFilter * * DESCRIPTION * Enable / Disable filtering of bad language. * * INPUTS * Filter - True to enable filtering, false to disable. * * RESULT * True if request successful * ******************************************************************************/ bool Session::SetBadLanguageFilter(bool enabled) { HRESULT hr = mChat->SetLangFilter(enabled); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: SetLangFilter() failed HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } /****************************************************************************** * * NAME * Session::SendPublicMessage * * DESCRIPTION * Send a public message to all users in our channel. * * INPUTS * Message - Message to send * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPublicMessage(const char* message) { if (message) { return SUCCEEDED(mChat->RequestPublicMessage(message)); } return false; } bool Session::SendPublicMessage(const wchar_t* message) { if (message) { if (IsAnsiText(message)) { char ansiMessage[1024]; wcstombs(ansiMessage, message, sizeof(ansiMessage)); return SUCCEEDED(mChat->RequestPublicMessage(ansiMessage)); } else { return SUCCEEDED(mChat->RequestPublicUnicodeMessage(message)); } } return false; } /****************************************************************************** * * NAME * Session::SendPublicAction * * DESCRIPTION * Send an actions to all users in our channel. * * INPUTS * Action - Action message * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPublicAction(const char* action) { if (action) { return SUCCEEDED(mChat->RequestPublicAction(action)); } return false; } bool Session::SendPublicAction(const wchar_t* action) { if (action) { if (IsAnsiText(action)) { char ansiAction[1024]; wcstombs(ansiAction, action, sizeof(ansiAction)); return SUCCEEDED(mChat->RequestPublicAction(ansiAction)); } else { return SUCCEEDED(mChat->RequestPublicUnicodeAction(action)); } } return false; } /****************************************************************************** * * NAME * Session::SendPrivateMessage * * DESCRIPTION * Send a private message to a single user. * * INPUTS * Username - Name of user to send private message to. * Message - Message to send. * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPrivateMessage(const wchar_t* username, const wchar_t* message) { if (username && message) { WOL::User user; memset(&user, 0, sizeof(user)); wcstombs((char*)user.name, username, sizeof(user.name)); user.name[sizeof(user.name) - 1] = 0; if (IsAnsiText(message)) { char ansiMessage[512]; wcstombs(ansiMessage, message, sizeof(ansiMessage)); return SUCCEEDED(mChat->RequestPrivateMessage(&user, ansiMessage)); } return SUCCEEDED(mChat->RequestPrivateUnicodeMessage(&user, message)); } return false; } /****************************************************************************** * * NAME * Session::SendPrivateMessage * * DESCRIPTION * Send a private message to a set of users. * * INPUTS * Users - List of users to send message * Message - Message to send. * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPrivateMessage(const UserList& users, const char* message) { if (!users.empty() && message) { NativeWOLUserList wolUsers(users); return SUCCEEDED(mChat->RequestPrivateMessage(wolUsers, message)); } return false; } bool Session::SendPrivateMessage(const UserList& users, const wchar_t* message) { if (!users.empty() && message) { NativeWOLUserList wolUsers(users); if (IsAnsiText(message)) { char ansiMessage[512]; wcstombs(ansiMessage, message, sizeof(ansiMessage)); return SUCCEEDED(mChat->RequestPrivateMessage(wolUsers, ansiMessage)); } return SUCCEEDED(mChat->RequestPrivateUnicodeMessage(wolUsers, message)); } return false; } /****************************************************************************** * * NAME * Session::SendPrivateAction * * DESCRIPTION * Send a private action message to a set of users. * * INPUTS * Users - List of users to send message to. * Action - Action message to send. * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPrivateAction(const UserList& users, const char* action) { if (!users.empty() && action) { NativeWOLUserList wolUsers(users); return SUCCEEDED(mChat->RequestPrivateAction(wolUsers, action)); } return false; } bool Session::SendPrivateAction(const UserList& users, const wchar_t* action) { if (!users.empty() && action) { NativeWOLUserList wolUsers(users); if (IsAnsiText(action)) { char ansiAction[1024]; wcstombs(ansiAction, action, sizeof(ansiAction)); return SUCCEEDED(mChat->RequestPrivateAction(wolUsers, ansiAction)); } return SUCCEEDED(mChat->RequestPrivateUnicodeAction(wolUsers, action)); } return false; } /****************************************************************************** * * NAME * Session::SendPublicGameOptions * * DESCRIPTION * Send public game options * * INPUTS * Options - Options to send to all users in the channel. * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPublicGameOptions(const char* options) { if (options) { return SUCCEEDED(mChat->RequestPublicGameOptions(options)); } return false; } /****************************************************************************** * * NAME * Session::SendPrivateGameOptions * * DESCRIPTION * * INPUTS * Options - Options to send to specific users. * * RESULT * True if request successful * ******************************************************************************/ bool Session::SendPrivateGameOptions(const UserList& users, const char* options) { if (options) { for (unsigned int index = 0; index < users.size(); index++) { NativeWOLUserList wolUsers(users); HRESULT hr = mChat->RequestPrivateGameOptions(wolUsers, options); if (FAILED(hr)) { return false; } } return true; } return false; } bool Session::SendPrivateGameOptions(const wchar_t* user, const char* options) { if (user && options) { WOL::User wolUser; memset(&wolUser, 0, sizeof(WOL::User)); wcstombs((char*)wolUser.name, user, sizeof(wolUser.name)); wolUser.name[sizeof(wolUser.name) - 1] = 0; return SUCCEEDED(mChat->RequestPrivateGameOptions(&wolUser, options)); } return false; } /****************************************************************************** * * NAME * Session::GetLocaleStrings * * DESCRIPTION * Get a list of the WWOnline locale strings. * * INPUTS * Strings - List to fill with locale name strings. * * RESULT * NONE * ******************************************************************************/ void Session::GetLocaleStrings(std::vector& localeStrings) { localeStrings.clear(); int numLocales = 0; mChat->GetLocaleCount(&numLocales); for (int index = 0; index < numLocales; index++) { const char* name = NULL; mChat->GetLocaleString(&name, (WOL::Locale)index); localeStrings.push_back(name); } } /****************************************************************************** * * NAME * Session::SendGameResults * * DESCRIPTION * * INPUTS * Packet - Game results packet to send. * Length - Length of packet in bytes. * * RESULT * True if request sent successfully * ******************************************************************************/ bool Session::SendGameResults(unsigned char* packet, unsigned long length) { if (packet && mGameResultsServer.IsValid()) { mNetUtil->SetGameResMD5(true); const char* host = mGameResultsServer->GetHostAddress(); unsigned int port = mGameResultsServer->GetPort(); HRESULT hr = mNetUtil->RequestLargeGameresSend(host, port, packet, length); if (FAILED(hr)) { WWDEBUG_SAY(("WOLERROR: RequestLargeGameresSend() failed HRESULT = %s\n", GetChatErrorString(hr))); } return SUCCEEDED(hr); } return false; } /****************************************************************************** * * NAME * Session::EnablePinging * * DESCRIPTION * * INPUTS * * RESULT * NONE * ******************************************************************************/ void Session::EnablePinging(bool enable) { mPingEnable += ((enable == true) ? 1 : -1); } /****************************************************************************** * * NAME * Session::RequestPing * * DESCRIPTION * Request a ping to the specified address. * * INPUTS * Address - Address to ping (IE: irc.westwood.com) * Timeout - Maximum time to allow for response. * * RESULT * NONE * ******************************************************************************/ void Session::RequestPing(const char* address, int timeout) { if (address) { // If the address is already pending then do not add it again. std::vector::iterator iter = mPingRequests.begin(); while (iter != mPingRequests.end()) { if (stricmp(iter->GetHostAddress(), address) == 0) { // WWDEBUG_SAY(("WOLWARNING: Ping request already pending %s\n", address)); return; } iter++; } WWDEBUG_SAY(("WOL: Adding ping request %s\n", address)); RawPing ping(address, 0, timeout); mPingRequests.push_back(ping); } } /****************************************************************************** * * NAME * Session::MakePingRequests * * DESCRIPTION * Send out ping requests * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::MakePingRequests(void) { if (mPingEnable && (mPingRequests.size() > mPingsPending)) { for (unsigned int index = 0; index < mPingRequests.size(); index++) { RawPing* ping = &mPingRequests[index]; if (ping->GetHandle() == -1) { int handle = 0; HRESULT hr = mNetUtil->RequestPing(ping->GetHostAddress(), ping->GetTime(), &handle); if (SUCCEEDED(hr)) { WWDEBUG_SAY(("WOL: Pinging '%s' [%d]\n", ping->GetHostAddress(), handle)); ping->SetHandle(handle); mPingsPending++; } } } } } /****************************************************************************** * * NAME * Session::UpdatePingServerTime * * DESCRIPTION * Update the ping time of a ping server. * * INPUTS * Name - Host adddress of server to update. * Time - Ping time. * * RESULT * NONE * ******************************************************************************/ void Session::UpdatePingServerTime(const char* name, int time) { if (name) { // Automatically update ping server times. const PingServerList& pingers = GetPingServerList(); for (unsigned int index = 0; index < pingers.size(); index++) { const char* pinger = pingers[index]->GetHostAddress(); if (stricmp(name, pinger) == 0) { if (time < 0) { time = INT_MAX; } pingers[index]->SetPingTime(time); break; } } } } /****************************************************************************** * * NAME * Session::RequestUserIP * * DESCRIPTION * Ask the chat server for a users IP address * * INPUTS * Name of user * * RESULT * NONE * ******************************************************************************/ bool Session::RequestUserIP(char *user_name) { if (user_name) { WOL::User wolUser; memset(&wolUser, 0, sizeof(WOL::User)); strncpy((char*)wolUser.name, user_name, sizeof(wolUser.name)); wolUser.name[sizeof(wolUser.name) - 1] = 0; return SUCCEEDED(mChat->RequestUserIP(&wolUser)); } return false; } /****************************************************************************** * * NAME * Session::RequestInsiderStatus * * DESCRIPTION * Used to ask the chat server for if the currently logged in user is * an insider or not. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::RequestInsiderStatus(void) { if (mChat != NULL && mCurrentUser.IsValid ()) { WOL::User &user = mCurrentUser->GetData(); mChat->RequestInsiderStatus(&user); } } /****************************************************************************** * * NAME * Session::RequestServerTime * * DESCRIPTION * Used to ask the chat server for its current time. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void Session::RequestServerTime(void) { if (mChat != NULL) { mChat->RequestServerTime(); } } /****************************************************************************** * * NAME * Session::GetIGRObject * * DESCRIPTION * * INPUTS * NONE * * RESULT * ******************************************************************************/ const CComPtr& Session::GetIGRObject(void) { if (mIGRObject == NULL) { WWDEBUG_SAY(("WOL: Creating IID_IIGROptions object\n")); WOL::IIGROptions* igrObject = NULL; HRESULT hr = CoCreateInstance(WOL::CLSID_IGROptions, NULL, CLSCTX_INPROC_SERVER, WOL::IID_IIGROptions, (void**)&igrObject); if (SUCCEEDED(hr)) { HRESULT hr = igrObject->Init(); if (S_FALSE == hr) { WWDEBUG_SAY(("WOLWARNING: IGR settings not found\n")); } } else { WWDEBUG_SAY(("WOLERROR: Failed to create IID_IIGROptions\n")); } mIGRObject = igrObject; } return mIGRObject; } /****************************************************************************** * * NAME * Session::IsStoreLoginAllowed * * DESCRIPTION * Check if it is okay to save users login information. * * INPUTS * NONE * * RESULT * True if allowed to save login information. * ******************************************************************************/ bool Session::IsStoreLoginAllowed(void) { const CComPtr& igr = GetIGRObject(); if (igr) { HRESULT hr = igr->Is_Storing_Nicks_Allowed(); return (hr == S_OK); } return true; } /****************************************************************************** * * NAME * Session::IsAutoLoginAllowed * * DESCRIPTION * Check if it is okay to automatically login users. * * INPUTS * NONE * * RESULT * True if allowed to auto login. * ******************************************************************************/ bool Session::IsAutoLoginAllowed(void) { const CComPtr& igr = GetIGRObject(); if (igr) { HRESULT hr = igr->Is_Auto_Login_Allowed(); return (hr == S_OK); } return true; } /****************************************************************************** * * NAME * Session::IsRunRegAppAllowed * * DESCRIPTION * * INPUTS * NONE * * RESULT * True if allowed to run registration applet. * ******************************************************************************/ bool Session::IsRunRegAppAllowed(void) { const CComPtr& igr = GetIGRObject(); if (igr) { HRESULT hr = igr->Is_Running_Reg_App_Allowed(); return (hr == S_OK); } return true; } /****************************************************************************** * * NAME * ChatAdvisement::Create * * DESCRIPTION * Create a IChatEvents advisement * * INPUTS * Chat - IChat object * Sink - IChatEvents sink to advise. * * RESULT * Advisement - Instance of advisement * ******************************************************************************/ RefPtr ChatAdvisement::Create(const CComPtr& chat, const CComPtr& sink) { return new ChatAdvisement(chat, sink); } /****************************************************************************** * * NAME * ChatAdvisement::ChatAdvisement * * DESCRIPTION * Constructor * * INPUTS * Chat - IChat object * Sink - IChatEvents sink to advise. * * RESULT * NONE * ******************************************************************************/ ChatAdvisement::ChatAdvisement(const CComPtr& chat, const CComPtr& sink) : mChat(chat), mChatCookie(0) { if (mChat && sink) { AtlAdvise(mChat, sink, WOL::IID_IChatEvent, &mChatCookie); } } /****************************************************************************** * * NAME * ChatAdvisement::~ChatAdvisement * * DESCRIPTION * Destructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ ChatAdvisement::~ChatAdvisement() { if (mChat) { AtlUnadvise(mChat, WOL::IID_IChatEvent, mChatCookie); } } } // namespace WWOnline