Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

785 lines
25 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "vguitextwindow.h"
  9. #include <networkstringtabledefs.h>
  10. #include <cdll_client_int.h>
  11. #include "inputsystem/iinputsystem.h"
  12. #include <vgui/IScheme.h>
  13. #include <vgui/ILocalize.h>
  14. #include <vgui/ISurface.h>
  15. #include <filesystem.h>
  16. #include <keyvalues.h>
  17. #include <convar.h>
  18. #include <vgui_controls/ImageList.h>
  19. #include <vgui_controls/TextEntry.h>
  20. #include <vgui_controls/Button.h>
  21. #include <game/client/iviewport.h>
  22. #include "cs_gamerules.h"
  23. #include "matchmaking/imatchframework.h"
  24. #include "tier1/netadr.h"
  25. #include "gametypes/igametypes.h"
  26. #include "gameui_interface.h"
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. using namespace vgui;
  30. extern INetworkStringTable *g_pStringTableInfoPanel;
  31. #define TEMP_HTML_FILE "textwindow_temp.html"
  32. ConVar cl_disablehtmlmotd( "cl_disablehtmlmotd", "0", FCVAR_ARCHIVE, "Disable HTML motds." );
  33. ConVar cl_motd_competitive_timeout( "cl_motd_competitive_timeout", "80", FCVAR_DEVELOPMENTONLY, "Competitive motd timeout in seconds." );
  34. extern ConVar sv_disable_motd;
  35. //=============================================================================
  36. // HPE_BEGIN:
  37. // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
  38. // of options. Passing a command string is dangerous and allowed a server network
  39. // message to run arbitrary commands on the client.
  40. //=============================================================================
  41. CON_COMMAND( showinfo, "Shows a info panel: <type> <title> <message> [<command number>]" )
  42. {
  43. if ( !GetViewPortInterface() )
  44. return;
  45. if ( args.ArgC() < 4 )
  46. return;
  47. IViewPortPanel * panel = GetViewPortInterface()->FindPanelByName( PANEL_INFO );
  48. if ( panel )
  49. {
  50. KeyValues *kv = new KeyValues("data");
  51. kv->SetInt( "type", Q_atoi(args[ 1 ]) );
  52. kv->SetString( "title", args[ 2 ] );
  53. kv->SetString( "message", args[ 3 ] );
  54. if ( args.ArgC() == 5 )
  55. kv->SetString( "command", args[ 4 ] );
  56. panel->SetData( kv );
  57. GetViewPortInterface()->ShowPanel( panel, true );
  58. kv->deleteThis();
  59. }
  60. else
  61. {
  62. Msg("Couldn't find info panel.\n" );
  63. }
  64. }
  65. //=============================================================================
  66. // HPE_END
  67. //=============================================================================
  68. //-----------------------------------------------------------------------------
  69. // Purpose: Constructor
  70. //-----------------------------------------------------------------------------
  71. CTextWindow::CTextWindow(IViewPort *pViewPort) : Frame(NULL, PANEL_INFO )
  72. {
  73. m_dblTimeExecutedExitCommand = 0;
  74. m_bHasMotd = false;
  75. m_uiTimestampStarted = 0;
  76. m_uiTimestampInfoLabelUpdated = 0;
  77. m_bForcingWindowCloseRegardlessOfTime = false;
  78. // initialize dialog
  79. m_pViewPort = pViewPort;
  80. // SetTitle("", true);
  81. m_szTitle[0] = '\0';
  82. m_szMessage[0] = '\0';
  83. m_szMessageFallback[0] = '\0';
  84. //=============================================================================
  85. // HPE_BEGIN:
  86. // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
  87. // of options. Passing a command string is dangerous and allowed a server network
  88. // message to run arbitrary commands on the client.
  89. //=============================================================================
  90. m_nExitCommand = TEXTWINDOW_CMD_NONE;
  91. //=============================================================================
  92. // HPE_END
  93. //=============================================================================
  94. // load the new scheme early!!
  95. SetScheme("ClientScheme");
  96. SetMoveable(false);
  97. SetSizeable(false);
  98. SetProportional(true);
  99. // hide the system buttons
  100. SetTitleBarVisible( false );
  101. m_pTextMessage = new TextEntry(this, "TextMessage");
  102. #if defined( ENABLE_CHROMEHTMLWINDOW )
  103. m_pHTMLMessage = new CMOTDHTML( this,"HTMLMessage" );
  104. #else
  105. m_pHTMLMessage = NULL;
  106. #endif
  107. m_pTitleLabel = new Label( this, "MessageTitle", "Message Title" );
  108. m_pInfoLabelTicker = new Label( this, "InfoLabelTicker", " " );
  109. m_pOK = new Button(this, "ok", "#PropertyDialog_OK");
  110. m_pOK->SetCommand("okay");
  111. m_pTextMessage->SetMultiline( true );
  112. m_nContentType = TYPE_TEXT;
  113. SetMouseInputEnabled( false );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. void CTextWindow::ApplySchemeSettings( IScheme *pScheme )
  119. {
  120. BaseClass::ApplySchemeSettings( pScheme );
  121. LoadControlSettings("Resource/UI/TextWindow.res");
  122. Reset();
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose: Destructor
  126. //-----------------------------------------------------------------------------
  127. CTextWindow::~CTextWindow()
  128. {
  129. g_pInputSystem->SetSteamControllerMode( NULL, this );
  130. // remove temp file again
  131. g_pFullFileSystem->RemoveFile( TEMP_HTML_FILE, "DEFAULT_WRITE_PATH" );
  132. }
  133. void CTextWindow::Reset( void )
  134. {
  135. g_pInputSystem->SetSteamControllerMode( NULL, this );
  136. //=============================================================================
  137. // HPE_BEGIN:
  138. // [Forrest] Replace strange hard-coded default message with hard-coded error message.
  139. //=============================================================================
  140. Q_strcpy( m_szTitle, "Error loading info message." );
  141. Q_strcpy( m_szMessage, "" );
  142. Q_strcpy( m_szMessageFallback, "" );
  143. //=============================================================================
  144. // HPE_END
  145. //=============================================================================
  146. //=============================================================================
  147. // HPE_BEGIN:
  148. // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
  149. // of options. Passing a command string is dangerous and allowed a server network
  150. // message to run arbitrary commands on the client.
  151. //=============================================================================
  152. m_nExitCommand = TEXTWINDOW_CMD_NONE;
  153. //=============================================================================
  154. // HPE_END
  155. //=============================================================================
  156. m_nContentType = TYPE_TEXT;
  157. m_bHasMotd = false;
  158. Update();
  159. }
  160. void CTextWindow::ShowText( const char *text)
  161. {
  162. m_pTextMessage->SetVisible( true );
  163. m_pTextMessage->SetText( text );
  164. m_pTextMessage->GotoTextStart();
  165. m_bHasMotd = !!strlen(text);
  166. }
  167. void CTextWindow::ShowURL( const char *URL, bool bAllowUserToDisable )
  168. {
  169. #if defined( ENABLE_CHROMEHTMLWINDOW )
  170. if ( bAllowUserToDisable && cl_disablehtmlmotd.GetBool() && !GetNumSecondsRequiredByServer() )
  171. {
  172. // User has disabled HTML TextWindows. Show the fallback as text only.
  173. if ( g_pStringTableInfoPanel )
  174. {
  175. int index = g_pStringTableInfoPanel->FindStringIndex( m_szMessageFallback );
  176. if ( index != ::INVALID_STRING_INDEX )
  177. {
  178. int length = 0;
  179. const char *data = (const char *)g_pStringTableInfoPanel->GetStringUserData( index, &length );
  180. if ( data && data[0] )
  181. {
  182. ShowText( data );
  183. }
  184. }
  185. }
  186. return;
  187. }
  188. //
  189. // Apply URL pattern replacements
  190. //
  191. char chUrlBufferAfterPatternReplacements[ 1024 ] = {0};
  192. Q_strncpy( chUrlBufferAfterPatternReplacements, URL, sizeof( chUrlBufferAfterPatternReplacements ) );
  193. CFmtStr fmtPattern;
  194. CFmtStr fmtReplacement;
  195. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%steamid%" );
  196. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%llu", steamapicontext->SteamUser()->GetSteamID().ConvertToUint64() );
  197. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  198. {
  199. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  200. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  201. break;
  202. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  203. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  204. }
  205. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%map%" );
  206. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%s", engine->GetLevelNameShort() );
  207. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  208. {
  209. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  210. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  211. break;
  212. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  213. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  214. }
  215. static ConVarRef game_mode( "game_mode" );
  216. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%game_mode%" );
  217. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%u", game_mode.GetInt() );
  218. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  219. {
  220. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  221. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  222. break;
  223. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  224. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  225. }
  226. static ConVarRef game_type( "game_type" );
  227. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%game_type%" );
  228. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%u", game_type.GetInt() );
  229. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  230. {
  231. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  232. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  233. break;
  234. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  235. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  236. }
  237. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%serveraddr%" );
  238. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%s", ( g_pMatchFramework && g_pMatchFramework->GetMatchSession() ) ? netadr_t( g_pMatchFramework->GetMatchSession()->GetSessionSettings()->GetString( "server/adronline" ) ).ToString() : "0.0.0.0:0" );
  239. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  240. {
  241. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  242. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  243. break;
  244. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  245. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  246. }
  247. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%serverip%" );
  248. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%s", ( g_pMatchFramework && g_pMatchFramework->GetMatchSession() ) ? netadr_t( g_pMatchFramework->GetMatchSession()->GetSessionSettings()->GetString( "server/adronline" ) ).ToString( true ) : "0.0.0.0" );
  249. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  250. {
  251. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  252. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  253. break;
  254. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  255. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  256. }
  257. fmtPattern.Clear(); fmtPattern.AppendFormat( "%s", "%serverport%" );
  258. fmtReplacement.Clear(); fmtReplacement.AppendFormat( "%u", ( g_pMatchFramework && g_pMatchFramework->GetMatchSession() ) ? netadr_t( g_pMatchFramework->GetMatchSession()->GetSessionSettings()->GetString( "server/adronline" ) ).GetPort() : 0 );
  259. while ( char *pszReplace = strstr( chUrlBufferAfterPatternReplacements, fmtPattern.Access() ) )
  260. {
  261. size_t numBytes = Q_strlen( pszReplace + fmtPattern.Length() );
  262. if ( pszReplace + fmtReplacement.Length() + numBytes + 1 >= &chUrlBufferAfterPatternReplacements[ sizeof( chUrlBufferAfterPatternReplacements ) ] )
  263. break;
  264. Q_memmove( pszReplace + fmtReplacement.Length(), pszReplace + fmtPattern.Length(), numBytes );
  265. Q_memcpy( pszReplace, fmtReplacement.Access(), fmtReplacement.Length() );
  266. }
  267. //
  268. // Display the replaced URL
  269. //
  270. m_pHTMLMessage->SetVisible( true );
  271. m_pHTMLMessage->OpenURL( chUrlBufferAfterPatternReplacements, NULL );
  272. m_bHasMotd = 1;
  273. #endif
  274. }
  275. void CTextWindow::ShowIndex( const char *entry)
  276. {
  277. const char *data = NULL;
  278. int length = 0;
  279. if ( NULL == g_pStringTableInfoPanel )
  280. return;
  281. int index = g_pStringTableInfoPanel->FindStringIndex( m_szMessage );
  282. if ( index != ::INVALID_STRING_INDEX )
  283. data = (const char *)g_pStringTableInfoPanel->GetStringUserData( index, &length );
  284. if ( !data || !data[0] )
  285. return; // nothing to show
  286. // is this a web URL ?
  287. if ( StringHasPrefixCaseSensitive( data, "http://" ) )
  288. {
  289. ShowURL( data );
  290. return;
  291. }
  292. // try to figure out if this is HTML or not
  293. if ( data[0] != '<' )
  294. {
  295. ShowText( data );
  296. return;
  297. }
  298. // data is a HTML, we have to write to a file and then load the file
  299. FileHandle_t hFile = g_pFullFileSystem->Open( TEMP_HTML_FILE, "wb", "DEFAULT_WRITE_PATH" );
  300. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  301. return;
  302. g_pFullFileSystem->Write( data, length, hFile );
  303. g_pFullFileSystem->Close( hFile );
  304. if ( g_pFullFileSystem->Size( TEMP_HTML_FILE ) != (unsigned int)length )
  305. return; // something went wrong while writing
  306. ShowFile( TEMP_HTML_FILE );
  307. }
  308. void CTextWindow::ShowHtmlString(const char* data)
  309. {
  310. int length = strlen(data);
  311. // data is a HTML, we have to write to a file and then load the file
  312. FileHandle_t hFile = g_pFullFileSystem->Open( TEMP_HTML_FILE, "wb", "DEFAULT_WRITE_PATH" );
  313. if ( hFile == FILESYSTEM_INVALID_HANDLE )
  314. return;
  315. g_pFullFileSystem->Write( data, length, hFile );
  316. g_pFullFileSystem->Close( hFile );
  317. if ( g_pFullFileSystem->Size( TEMP_HTML_FILE ) != (unsigned int)length )
  318. return; // something went wrong while writing
  319. ShowFile( TEMP_HTML_FILE );
  320. }
  321. void CTextWindow::ShowFile( const char *filename )
  322. {
  323. if ( Q_stristr( filename, ".htm" ) || Q_stristr( filename, ".html" ) )
  324. {
  325. // it's a local HTML file
  326. char localURL[ _MAX_PATH + 7 ];
  327. Q_strncpy( localURL, "file://", sizeof( localURL ) );
  328. char pPathData[ _MAX_PATH ];
  329. g_pFullFileSystem->GetLocalPath( filename, pPathData, sizeof(pPathData) );
  330. Q_strncat( localURL, pPathData, sizeof( localURL ), COPY_ALL_CHARACTERS );
  331. ShowURL( localURL );
  332. }
  333. else
  334. {
  335. // read from local text from file
  336. FileHandle_t f = g_pFullFileSystem->Open( m_szMessage, "rb", "GAME" );
  337. if ( !f )
  338. return;
  339. char buffer[2048];
  340. int size = min( g_pFullFileSystem->Size( f ), sizeof(buffer)-1 ); // just allow 2KB
  341. g_pFullFileSystem->Read( buffer, size, f );
  342. g_pFullFileSystem->Close( f );
  343. buffer[size]=0; //terminate string
  344. ShowText( buffer );
  345. }
  346. }
  347. void CTextWindow::Update( void )
  348. {
  349. SetTitle( m_szTitle, false );
  350. m_pTitleLabel->SetText( m_szTitle );
  351. #if defined( ENABLE_CHROMEHTMLWINDOW )
  352. m_pHTMLMessage->SetVisible( false );
  353. #endif
  354. m_pTextMessage->SetVisible( false );
  355. if ( m_nContentType == TYPE_INDEX )
  356. {
  357. ShowIndex( m_szMessage );
  358. }
  359. else if ( m_nContentType == TYPE_URL )
  360. {
  361. // Only allow "http://" and "https://" URLs. Filter out other types.
  362. // "javascript:" URLs, for example, provide a way of executing arbitrary javascript on whatever page is currently loaded
  363. if ( !( StringHasPrefix( m_szMessage, "http://" ) || StringHasPrefix( m_szMessage, "https://" ) || StringHasPrefix( m_szMessage, "about:blank" ) ) )
  364. {
  365. return;
  366. }
  367. ShowURL( m_szMessage );
  368. }
  369. else if ( m_nContentType == TYPE_FILE )
  370. {
  371. ShowFile( m_szMessage );
  372. }
  373. else if ( m_nContentType == TYPE_TEXT )
  374. {
  375. ShowText( m_szMessage );
  376. }
  377. else
  378. {
  379. DevMsg("CTextWindow::Update: unknown content type %i\n", m_nContentType );
  380. }
  381. }
  382. int CTextWindow::GetNumSecondsRequiredByServer() const
  383. {
  384. if ( !g_pGameTypes )
  385. return 0;
  386. int numSecondsRequired = g_pGameTypes->GetCurrentServerSettingInt( "sv_require_motd_seconds", 0 );
  387. if ( numSecondsRequired < 0 )
  388. return 0;
  389. if ( numSecondsRequired > 35 )
  390. numSecondsRequired = 35; // never allow > 35 second ads
  391. return numSecondsRequired;
  392. }
  393. int CTextWindow::GetNumSecondsSponsorRequiredRemaining() const
  394. {
  395. int numSecondsRemaining = 0;
  396. if ( !m_bForcingWindowCloseRegardlessOfTime )
  397. {
  398. int numSecondsShownAlready = int( Plat_MSTime() - m_uiTimestampStarted ) / 1000;
  399. int numSecondsRequired = GetNumSecondsRequiredByServer();
  400. if ( ( numSecondsRequired > 0 ) && ( numSecondsShownAlready < numSecondsRequired ) )
  401. numSecondsRemaining = ( numSecondsRequired - numSecondsShownAlready );
  402. }
  403. static ConVarRef cv_ignore_ui_activate_key( "ignore_ui_activate_key" );
  404. if ( numSecondsRemaining != cv_ignore_ui_activate_key.GetInt() )
  405. cv_ignore_ui_activate_key.SetValue( numSecondsRemaining );
  406. return numSecondsRemaining;
  407. }
  408. void CTextWindow::OnCommand( const char *command )
  409. {
  410. if ( GetNumSecondsSponsorRequiredRemaining() > 0 )
  411. return;
  412. if ( !Q_strcmp( command, "okay" ) )
  413. {
  414. //=============================================================================
  415. // HPE_BEGIN:
  416. // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
  417. // of options. Passing a command string is dangerous and allowed a server network
  418. // message to run arbitrary commands on the client.
  419. //=============================================================================
  420. const char *pszCommand = NULL;
  421. switch ( m_nExitCommand )
  422. {
  423. case TEXTWINDOW_CMD_NONE:
  424. break;
  425. case TEXTWINDOW_CMD_JOINGAME:
  426. pszCommand = "joingame";
  427. break;
  428. case TEXTWINDOW_CMD_CHANGETEAM:
  429. pszCommand = "changeteam";
  430. break;
  431. case TEXTWINDOW_CMD_IMPULSE101:
  432. pszCommand = "impulse 101";
  433. break;
  434. case TEXTWINDOW_CMD_MAPINFO:
  435. pszCommand = "mapinfo";
  436. break;
  437. case TEXTWINDOW_CMD_CLOSED_HTMLPAGE:
  438. pszCommand = "closed_htmlpage";
  439. break;
  440. case TEXTWINDOW_CMD_CHOOSETEAM:
  441. pszCommand = "chooseteam";
  442. break;
  443. default:
  444. DevMsg("CTextWindow::OnCommand: unknown exit command value %i\n", m_nExitCommand );
  445. break;
  446. }
  447. m_dblTimeExecutedExitCommand = Plat_FloatTime();
  448. if ( ( pszCommand != NULL ) && !engine->IsDrawingLoadingImage() ) // don't execute commands while we are loading, we'll re-show MOTD after load finishes!
  449. {
  450. engine->ClientCmd_Unrestricted( pszCommand );
  451. }
  452. //=============================================================================
  453. // HPE_END
  454. //=============================================================================
  455. m_pViewPort->ShowPanel( this, false );
  456. }
  457. BaseClass::OnCommand(command);
  458. }
  459. void CTextWindow::OnKeyCodePressed( vgui::KeyCode code )
  460. {
  461. switch ( GetBaseButtonCode( code ) )
  462. {
  463. case KEY_XBUTTON_B:
  464. case KEY_XBUTTON_A:
  465. case KEY_XBUTTON_START:
  466. case KEY_XBUTTON_INACTIVE_START:
  467. OnCommand( "okay" );
  468. return;
  469. }
  470. BaseClass::OnKeyCodePressed( code );
  471. }
  472. void CTextWindow::SetData(KeyValues *data)
  473. {
  474. //=============================================================================
  475. // HPE_BEGIN:
  476. // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
  477. // of options. Passing a command string is dangerous and allowed a server network
  478. // message to run arbitrary commands on the client.
  479. //=============================================================================
  480. SetData( data->GetInt( "type" ), data->GetString( "title" ), data->GetString( "msg" ), data->GetString( "msg_fallback" ), data->GetInt( "cmd" ) );
  481. //=============================================================================
  482. // HPE_END
  483. //=============================================================================
  484. }
  485. //=============================================================================
  486. // HPE_BEGIN:
  487. // [Forrest] Replaced text window command string with TEXTWINDOW_CMD enumeration
  488. // of options. Passing a command string is dangerous and allowed a server network
  489. // message to run arbitrary commands on the client.
  490. //=============================================================================
  491. void CTextWindow::SetData( int type, const char *title, const char *message, const char *message_fallback, int command )
  492. {
  493. Q_strncpy( m_szTitle, "", sizeof( m_szTitle ) );
  494. Q_strncpy( m_szMessage, message, sizeof( m_szMessage ) );
  495. Q_strncpy( m_szMessageFallback, message_fallback, sizeof( m_szMessageFallback ) );
  496. m_nExitCommand = command;
  497. m_nContentType = type;
  498. Update();
  499. }
  500. //=============================================================================
  501. // HPE_END
  502. //=============================================================================
  503. //
  504. // Some HTML used to direct the browser control to a benign HTML file
  505. //
  506. static char sBrowserClose [] =
  507. "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">"
  508. "<html>"
  509. "<head><title>CSGO MOTD</title>"
  510. "<style type=\"text/css\">pre{font-family:Verdana,Tahoma;color:#FFFFFF;}body{background:#000000;margin-left:8px;margin-top:0px;}</style>"
  511. "</head>"
  512. "<body scroll=\"no\"><pre>You are playing Counter-Strike: Global Offensive</pre></body>"
  513. "</html>";
  514. //
  515. // Hack to delay the display of the HTML window. Must revisit.
  516. // ShowPanel now only closes the panel. ShowPanel2 shows the panel.
  517. //
  518. void CTextWindow::ShowPanel( bool bShow )
  519. {
  520. g_pInputSystem->SetSteamControllerMode( bShow ? "MenuControls" : NULL, this );
  521. if (bShow)
  522. return;
  523. if ( BaseClass::IsVisible() == bShow )
  524. return;
  525. m_pViewPort->ShowBackGround( bShow );
  526. ShowHtmlString( sBrowserClose );
  527. SetVisible( false );
  528. SetMouseInputEnabled( false );
  529. GetHud(0).EnableHud();
  530. if ( !bShow && ( Plat_FloatTime() - m_dblTimeExecutedExitCommand > 1.0 ) )
  531. { // If something is trying to hide us and it's not because user clicked
  532. // the OKAY button, then trigger the commands associated with OKAY button
  533. m_bForcingWindowCloseRegardlessOfTime = true;
  534. OnCommand( "okay" );
  535. }
  536. // reset motd
  537. m_bHasMotd = false;
  538. }
  539. void CTextWindow::ShowPanel2( bool bShow )
  540. {
  541. if ( (CSGameRules() && CSGameRules()->IsQueuedMatchmaking()) || sv_disable_motd.GetBool() )
  542. bShow = false;
  543. g_pInputSystem->SetSteamControllerMode( bShow ? "MenuControls" : NULL, this );
  544. if ( BaseClass::IsVisible() == bShow )
  545. return;
  546. m_pViewPort->ShowBackGround( bShow );
  547. if ( bShow )
  548. {
  549. GetHud(0).DisableHud();
  550. Activate();
  551. SetVisible( true );
  552. SetMouseInputEnabled( true );
  553. if ( m_pInfoLabelTicker )
  554. {
  555. m_pInfoLabelTicker->SetVisible( false );
  556. m_pInfoLabelTicker->SetText( L" " );
  557. }
  558. m_bForcingWindowCloseRegardlessOfTime = false;
  559. m_uiTimestampStarted = Plat_MSTime();
  560. if ( !m_uiTimestampStarted )
  561. --m_uiTimestampStarted;
  562. m_uiTimestampInfoLabelUpdated = m_uiTimestampStarted - 1000;
  563. }
  564. else
  565. {
  566. ShowPanel( false );
  567. }
  568. }
  569. void CTextWindow::PaintBackground()
  570. {
  571. BaseClass::PaintBackground();
  572. if ( m_uiTimestampStarted && IsVisible() &&
  573. CSGameRules() && CSGameRules()->IsQueuedMatchmaking() &&
  574. ( int( Plat_MSTime() - m_uiTimestampStarted ) > 1000*cl_motd_competitive_timeout.GetInt() ) )
  575. {
  576. m_bForcingWindowCloseRegardlessOfTime = true;
  577. m_uiTimestampStarted = 0;
  578. OnCommand( "okay" );
  579. return;
  580. }
  581. if ( m_pInfoLabelTicker )
  582. {
  583. // Tick the time that the MOTD has been visible
  584. bool bVisible = false;
  585. if ( IsVisible() )
  586. {
  587. bVisible = true;
  588. if ( Plat_MSTime() - m_uiTimestampInfoLabelUpdated >= 1000 )
  589. {
  590. wchar_t wchSecs[64] = {};
  591. int numSecondsRemaining = GetNumSecondsSponsorRequiredRemaining();
  592. if ( numSecondsRemaining > 0 )
  593. {
  594. V_snwprintf( wchSecs, Q_ARRAYSIZE( wchSecs ), L"%u", numSecondsRemaining );
  595. wchar_t wchBufferText[256] = {};
  596. if ( const wchar_t *pwszToken = g_pVGuiLocalize->Find( "#SFUI_MOTD_RegionalServerSponsor" ) )
  597. {
  598. g_pVGuiLocalize->ConstructString( wchBufferText, sizeof( wchBufferText ), pwszToken, 1, wchSecs );
  599. }
  600. m_pInfoLabelTicker->SetText( wchBufferText );
  601. }
  602. else
  603. {
  604. m_pInfoLabelTicker->SetText( L" " );
  605. bVisible = false;
  606. }
  607. m_uiTimestampInfoLabelUpdated = Plat_MSTime();
  608. }
  609. }
  610. if ( bVisible != m_pInfoLabelTicker->IsVisible() )
  611. {
  612. m_pInfoLabelTicker->SetVisible( bVisible );
  613. }
  614. }
  615. if ( IsVisible() == false || GetAlpha() <= 0 )
  616. {
  617. m_bForcingWindowCloseRegardlessOfTime = true;
  618. OnCommand( "okay" );
  619. }
  620. }
  621. bool CTextWindow::HasMotd()
  622. {
  623. if ( m_bHasMotd == false )
  624. {
  625. // User has disabled HTML TextWindows. Show the fallback as text only.
  626. if ( g_pStringTableInfoPanel )
  627. {
  628. int index = g_pStringTableInfoPanel->FindStringIndex( m_szMessage );
  629. if ( index != ::INVALID_STRING_INDEX )
  630. {
  631. int length = 0;
  632. const char *data = ( const char * )g_pStringTableInfoPanel->GetStringUserData( index, &length );
  633. if ( data && data[0] )
  634. {
  635. ShowText( data );
  636. }
  637. }
  638. }
  639. }
  640. return m_bHasMotd;
  641. }
  642. bool CTextWindow::CMOTDHTML::OnStartRequest( const char *url, const char *target, const char *pchPostData, bool bIsRedirect )
  643. {
  644. if ( Q_strstr( url, "steam://" ) )
  645. return false;
  646. return BaseClass::OnStartRequest( url, target, pchPostData, bIsRedirect );
  647. }