Team Fortress 2 Source Code as on 22/4/2020
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.

1576 lines
43 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // BUG.CPP
  4. //
  5. // Tracker bridge
  6. //=====================================================================================//
  7. #include "vxconsole.h"
  8. // two bug systems, certain games are tied to a specific system
  9. #define BUG_REPORTER_DLLNAME_1 "bugreporter.dll"
  10. #define BUG_REPORTER_DLLNAME_2 "bugreporter_filequeue.dll"
  11. #define BUG_REPOSITORY_URL "\\\\fileserver\\bugs"
  12. #define REPOSITORY_VALIDATION_FILE "info.txt"
  13. #define BUG_ERRORTITLE "Bug Error"
  14. #define BUG_COLOR ( RGB( 0,255,255 ) )
  15. HWND g_bug_hWnd;
  16. HMODULE g_bug_hBugReporter1;
  17. HMODULE g_bug_hBugReporter2;
  18. IBugReporter *g_bug_pReporter1;
  19. IBugReporter *g_bug_pReporter2;
  20. IBugReporter *g_bug_pReporter;
  21. char g_bug_szTitle[512];
  22. char g_bug_szDescription[1024];
  23. char g_bug_szOwner[128];
  24. char g_bug_szSeverity[128];
  25. char g_bug_szReportType[128];
  26. char g_bug_szPriority[128];
  27. char g_bug_szArea[128];
  28. char g_bug_szMapNumber[128];
  29. int g_bug_GameType;
  30. bool g_bug_bActive;
  31. char g_bug_szScreenshot[MAX_PATH];
  32. char g_bug_szSavegame[MAX_PATH];
  33. char g_bug_szBSPName[MAX_PATH];
  34. xrMapInfo_t g_bug_mapInfo;
  35. bool g_bug_bCompressScreenshot;
  36. bool g_bug_bFirstCommand;
  37. struct GameSystem_t
  38. {
  39. const char *pFriendlyName;
  40. const char *pGameName;
  41. bool bUsesSystem1;
  42. };
  43. GameSystem_t g_Games[] =
  44. {
  45. { "Half Life 2", "hl2", true },
  46. { "Episode 1", "episodic", true },
  47. { "Episode 2", "ep2", true },
  48. { "Portal", "portal", false },
  49. { "Team Fortress 2", "tf", false },
  50. };
  51. static const char *GetRepositoryURL( void )
  52. {
  53. const char *pURL = g_bug_pReporter->GetRepositoryURL();
  54. if ( pURL )
  55. {
  56. return pURL;
  57. }
  58. return BUG_REPOSITORY_URL;
  59. }
  60. const char *GetSubmissionURL( int bugid )
  61. {
  62. const char *pURL = g_bug_pReporter->GetSubmissionURL();
  63. if ( pURL )
  64. {
  65. return pURL;
  66. }
  67. static char url[MAX_PATH];
  68. Q_snprintf( url, sizeof(url), "%s/%i", GetRepositoryURL(), bugid );
  69. return url;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // BugReporter_SelectReporter
  73. //
  74. //-----------------------------------------------------------------------------
  75. bool BugReporter_SelectReporter( const char *pGameName )
  76. {
  77. int system = -1;
  78. for ( int i = 0; i < ARRAYSIZE( g_Games ); i++ )
  79. {
  80. if ( pGameName && !V_stricmp( g_Games[i].pGameName, pGameName ) )
  81. {
  82. system = i;
  83. break;
  84. }
  85. }
  86. if ( system == -1 )
  87. {
  88. // not found, slam to first
  89. system = 0;
  90. }
  91. // games uses different systems
  92. int oldGameType = g_bug_GameType;
  93. g_bug_GameType = system;
  94. if ( g_Games[system].bUsesSystem1 )
  95. {
  96. g_bug_pReporter = g_bug_pReporter1;
  97. }
  98. else
  99. {
  100. g_bug_pReporter = g_bug_pReporter2;
  101. }
  102. // force the game area
  103. if ( g_Games[g_bug_GameType].bUsesSystem1 )
  104. {
  105. strcpy( g_bug_szArea, "XBOX 360" );
  106. }
  107. else
  108. {
  109. strcpy( g_bug_szArea, g_Games[g_bug_GameType].pFriendlyName );
  110. }
  111. bool bChanged = ( oldGameType != g_bug_GameType );
  112. return bChanged;
  113. }
  114. //-----------------------------------------------------------------------------
  115. // BugReporter_LoadDLL
  116. //
  117. //-----------------------------------------------------------------------------
  118. IBugReporter *BugReporter_LoadDLL( const char *pDLLName, HMODULE *phModule )
  119. {
  120. HMODULE hModule;
  121. IBugReporter *pBugReporter;
  122. *phModule = NULL;
  123. hModule = LoadLibrary( pDLLName );
  124. if ( !hModule )
  125. {
  126. Sys_MessageBox( BUG_ERRORTITLE, "Could not open '%s'\n", pDLLName );
  127. return NULL;
  128. }
  129. FARPROC pCreateInterface = GetProcAddress( hModule, CREATEINTERFACE_PROCNAME );
  130. if ( !pCreateInterface )
  131. {
  132. Sys_MessageBox( BUG_ERRORTITLE, "Missing '%s' interface for '%s'\n", CREATEINTERFACE_PROCNAME, pDLLName );
  133. return NULL;
  134. }
  135. pBugReporter = (IBugReporter *)((CreateInterfaceFn)pCreateInterface)( INTERFACEVERSION_BUGREPORTER, NULL );
  136. if ( !pBugReporter )
  137. {
  138. Sys_MessageBox( BUG_ERRORTITLE, "Missing interface '%s' for '%s'\n", INTERFACEVERSION_BUGREPORTER, pDLLName );
  139. return NULL;
  140. }
  141. bool bSuccess = pBugReporter->Init( NULL );
  142. if ( !bSuccess )
  143. {
  144. return NULL;
  145. }
  146. *phModule = hModule;
  147. return pBugReporter;
  148. }
  149. //-----------------------------------------------------------------------------
  150. // BugReporter_GetInterfaces
  151. //
  152. //-----------------------------------------------------------------------------
  153. bool BugReporter_GetInterfaces()
  154. {
  155. if ( !g_bug_pReporter1 )
  156. {
  157. g_bug_pReporter1 = BugReporter_LoadDLL( BUG_REPORTER_DLLNAME_1, &g_bug_hBugReporter1 );
  158. if ( !g_bug_pReporter1 )
  159. {
  160. Sys_MessageBox( BUG_ERRORTITLE, "PVCS intialization failed!\n" );
  161. }
  162. }
  163. if ( !g_bug_pReporter2 )
  164. {
  165. g_bug_pReporter2 = BugReporter_LoadDLL( BUG_REPORTER_DLLNAME_2, &g_bug_hBugReporter2 );
  166. if ( !g_bug_pReporter2 )
  167. {
  168. Sys_MessageBox( BUG_ERRORTITLE, "BugBait intialization failed!\n" );
  169. }
  170. }
  171. if ( g_bug_pReporter1 )
  172. {
  173. // determine submitter name
  174. ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: PVCS Username: '%s' Display As: '%s'\n", g_bug_pReporter1->GetUserName(), g_bug_pReporter1->GetUserName_Display() );
  175. }
  176. if ( g_bug_pReporter2 )
  177. {
  178. // determine submitter name
  179. ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: BugBait Username: '%s' Display As: '%s'\n", g_bug_pReporter2->GetUserName(), g_bug_pReporter2->GetUserName_Display() );
  180. }
  181. BugReporter_SelectReporter( NULL );
  182. // See if we can see the bug repository right now
  183. char fn[MAX_PATH];
  184. V_snprintf( fn, sizeof( fn ), "%s/%s", GetRepositoryURL(), REPOSITORY_VALIDATION_FILE );
  185. Sys_NormalizePath( fn, false );
  186. FILE *fp = fopen( fn, "rb" );
  187. if ( fp )
  188. {
  189. ConsoleWindowPrintf( BUG_COLOR, "PVCS Repository '%s'\n", GetRepositoryURL() );
  190. fclose( fp );
  191. }
  192. else
  193. {
  194. Sys_MessageBox( BUG_ERRORTITLE, "Unable to see '%s', check permissions and network connectivity.\n", fn );
  195. return false;
  196. }
  197. // success
  198. return true;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // BugReporter_FreeInterfaces
  202. //
  203. //-----------------------------------------------------------------------------
  204. void BugReporter_FreeInterfaces()
  205. {
  206. if ( g_bug_pReporter1 )
  207. {
  208. g_bug_pReporter1->Shutdown();
  209. g_bug_pReporter1 = NULL;
  210. FreeLibrary( g_bug_hBugReporter1 );
  211. g_bug_hBugReporter1 = NULL;
  212. }
  213. if ( g_bug_pReporter2 )
  214. {
  215. g_bug_pReporter2->Shutdown();
  216. g_bug_pReporter2 = NULL;
  217. FreeLibrary( g_bug_hBugReporter2 );
  218. g_bug_hBugReporter2 = NULL;
  219. }
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose: Expanded data destination object for CUtlBuffer output
  223. //-----------------------------------------------------------------------------
  224. struct JPEGDestinationManager_t
  225. {
  226. struct jpeg_destination_mgr pub; // public fields
  227. CUtlBuffer *pBuffer; // target/final buffer
  228. byte *buffer; // start of temp buffer
  229. };
  230. // choose an efficiently bufferaable size
  231. #define OUTPUT_BUF_SIZE 4096
  232. //-----------------------------------------------------------------------------
  233. // Purpose: Initialize destination --- called by jpeg_start_compress
  234. // before any data is actually written.
  235. //-----------------------------------------------------------------------------
  236. void init_destination( j_compress_ptr cinfo )
  237. {
  238. JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t *) cinfo->dest;
  239. // Allocate the output buffer --- it will be released when done with image
  240. dest->buffer = (byte *)
  241. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  242. OUTPUT_BUF_SIZE * sizeof(byte));
  243. dest->pub.next_output_byte = dest->buffer;
  244. dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: Empty the output buffer --- called whenever buffer fills up.
  248. // Input : boolean -
  249. //-----------------------------------------------------------------------------
  250. boolean empty_output_buffer( j_compress_ptr cinfo )
  251. {
  252. JPEGDestinationManager_t *dest = ( JPEGDestinationManager_t * ) cinfo->dest;
  253. CUtlBuffer *buf = dest->pBuffer;
  254. // Add some data
  255. buf->Put( dest->buffer, OUTPUT_BUF_SIZE );
  256. dest->pub.next_output_byte = dest->buffer;
  257. dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
  258. return TRUE;
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose: Terminate destination --- called by jpeg_finish_compress
  262. // after all data has been written. Usually needs to flush buffer.
  263. //
  264. // NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
  265. // application must deal with any cleanup that should happen even
  266. // for error exit.
  267. //-----------------------------------------------------------------------------
  268. void term_destination( j_compress_ptr cinfo )
  269. {
  270. JPEGDestinationManager_t *dest = (JPEGDestinationManager_t *) cinfo->dest;
  271. size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
  272. CUtlBuffer *buf = dest->pBuffer;
  273. /* Write any data remaining in the buffer */
  274. if (datacount > 0)
  275. {
  276. buf->Put( dest->buffer, datacount );
  277. }
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose: Set up functions for writing data to a CUtlBuffer instead of FILE *
  281. //-----------------------------------------------------------------------------
  282. void jpeg_UtlBuffer_dest( j_compress_ptr cinfo, CUtlBuffer *pBuffer )
  283. {
  284. JPEGDestinationManager_t *dest;
  285. /* The destination object is made permanent so that multiple JPEG images
  286. * can be written to the same file without re-executing jpeg_stdio_dest.
  287. * This makes it dangerous to use this manager and a different destination
  288. * manager serially with the same JPEG object, because their private object
  289. * sizes may be different. Caveat programmer.
  290. */
  291. if (cinfo->dest == NULL) { /* first time for this JPEG object? */
  292. cinfo->dest = (struct jpeg_destination_mgr *)
  293. (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  294. sizeof(JPEGDestinationManager_t));
  295. }
  296. dest = ( JPEGDestinationManager_t * ) cinfo->dest;
  297. dest->pub.init_destination = init_destination;
  298. dest->pub.empty_output_buffer = empty_output_buffer;
  299. dest->pub.term_destination = term_destination;
  300. dest->pBuffer = pBuffer;
  301. }
  302. //-----------------------------------------------------------------------------
  303. // BugDlg_CompressScreenshot
  304. //
  305. // Compress .BMP to .JPG, Delete .BMP
  306. //-----------------------------------------------------------------------------
  307. bool BugDlg_CompressScreenshot()
  308. {
  309. if ( !g_bug_szScreenshot[0] )
  310. {
  311. return false;
  312. }
  313. bool bSuccess = false;
  314. HBITMAP hBitmap = NULL;
  315. HDC hDC = NULL;
  316. char *pBMPBits = NULL;
  317. CUtlBuffer buf( 0, 0 );
  318. hBitmap = (HBITMAP)LoadImage( NULL, g_bug_szScreenshot, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
  319. if ( !hBitmap )
  320. goto cleanUp;
  321. hDC = CreateCompatibleDC( NULL );
  322. if ( !hDC )
  323. goto cleanUp;
  324. BITMAPINFO bitmapInfo;
  325. ZeroMemory( &bitmapInfo, sizeof( BITMAPINFO ) );
  326. bitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
  327. // populate the bmp info
  328. if ( !GetDIBits( hDC, hBitmap, 0, 0, NULL, &bitmapInfo, DIB_RGB_COLORS ) )
  329. goto cleanUp;
  330. pBMPBits = (char *)Sys_Alloc( bitmapInfo.bmiHeader.biSizeImage );
  331. if ( !pBMPBits )
  332. goto cleanUp;
  333. // could be bottom-up or top-down
  334. int nHeight = abs( bitmapInfo.bmiHeader.biHeight );
  335. if ( bitmapInfo.bmiHeader.biBitCount != 32 )
  336. {
  337. // unexpected format
  338. goto cleanUp;
  339. }
  340. if ( bitmapInfo.bmiHeader.biCompression != BI_RGB && bitmapInfo.bmiHeader.biCompression != BI_BITFIELDS )
  341. {
  342. // unexpected format
  343. goto cleanUp;
  344. }
  345. // don't want color masks
  346. bitmapInfo.bmiHeader.biCompression = BI_RGB;
  347. // get the raw bits
  348. if ( !GetDIBits( hDC, hBitmap, 0, nHeight, pBMPBits, &bitmapInfo, DIB_RGB_COLORS ) )
  349. goto cleanUp;
  350. JSAMPROW row_pointer[1];
  351. // compression data structure
  352. struct jpeg_compress_struct cinfo;
  353. ZeroMemory( &cinfo, sizeof( jpeg_compress_struct ) );
  354. // point at stderr
  355. struct jpeg_error_mgr jerr;
  356. cinfo.err = jpeg_std_error( &jerr );
  357. // create compressor
  358. jpeg_create_compress( &cinfo );
  359. // Hook CUtlBuffer to compression
  360. jpeg_UtlBuffer_dest( &cinfo, &buf );
  361. // image width and height, in pixels
  362. cinfo.image_width = bitmapInfo.bmiHeader.biWidth;
  363. cinfo.image_height = nHeight;
  364. cinfo.input_components = 3;
  365. cinfo.in_color_space = JCS_RGB;
  366. // Apply settings
  367. jpeg_set_defaults( &cinfo );
  368. jpeg_set_quality( &cinfo, 50, TRUE );
  369. // Start compressor
  370. jpeg_start_compress( &cinfo, TRUE);
  371. char *pRowBuffer = (char*)_alloca( bitmapInfo.bmiHeader.biWidth * 3 );
  372. row_pointer[0] = (JSAMPROW)pRowBuffer;
  373. // Write scanlines
  374. while ( cinfo.next_scanline < cinfo.image_height )
  375. {
  376. char *pSrc;
  377. if ( bitmapInfo.bmiHeader.biHeight < 0 )
  378. {
  379. // top down
  380. pSrc = &pBMPBits[cinfo.next_scanline * bitmapInfo.bmiHeader.biWidth * 4];
  381. }
  382. else
  383. {
  384. // bottom up
  385. pSrc = &pBMPBits[(nHeight-1 - cinfo.next_scanline) * bitmapInfo.bmiHeader.biWidth * 4];
  386. }
  387. // convert to BGR to RGB
  388. char *pDst = pRowBuffer;
  389. for ( int i=0; i<bitmapInfo.bmiHeader.biWidth; i++ )
  390. {
  391. pDst[0] = pSrc[2];
  392. pDst[1] = pSrc[1];
  393. pDst[2] = pSrc[0];
  394. pSrc += 4;
  395. pDst += 3;
  396. }
  397. jpeg_write_scanlines( &cinfo, row_pointer, 1 );
  398. }
  399. // Finalize image
  400. jpeg_finish_compress( &cinfo );
  401. char jpgFilename[MAX_PATH];
  402. Sys_StripExtension( g_bug_szScreenshot, jpgFilename, sizeof( jpgFilename ) );
  403. Sys_AddExtension( ".jpg", jpgFilename, sizeof( jpgFilename ) );
  404. if ( !Sys_SaveFile( jpgFilename, buf.Base(), buf.TellMaxPut() ) )
  405. goto cleanUp;
  406. // remove the uncompressed version
  407. unlink( g_bug_szScreenshot );
  408. strcpy( g_bug_szScreenshot, jpgFilename );
  409. bSuccess = true;
  410. cleanUp:
  411. if ( hBitmap )
  412. DeleteObject( hBitmap );
  413. if ( hDC )
  414. DeleteDC( hDC );
  415. if ( pBMPBits )
  416. Sys_Free( pBMPBits );
  417. return bSuccess;
  418. }
  419. //-----------------------------------------------------------------------------
  420. // BugDlg_GetAppData
  421. //
  422. //-----------------------------------------------------------------------------
  423. void BugDlg_GetAppData( HWND hWnd )
  424. {
  425. // clear stale data from previous query
  426. memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) );
  427. SetDlgItemText( hWnd, IDC_BUG_POSITION_LABEL, "" );
  428. SetDlgItemText( hWnd, IDC_BUG_ORIENTATION_LABEL, "" );
  429. SetDlgItemText( hWnd, IDC_BUG_MAP_LABEL, "" );
  430. SetDlgItemText( hWnd, IDC_BUG_BUILD_LABEL, "" );
  431. EnableWindow( GetDlgItem( hWnd, IDC_BUG_SAVEGAME ), false );
  432. EnableWindow( GetDlgItem( hWnd, IDC_BUG_INCLUDEBSP ), false );
  433. if ( g_connectedToApp )
  434. {
  435. // send to app, responds with position info
  436. if ( !g_bug_bFirstCommand )
  437. {
  438. // first command must send pause and status to be processed correctly
  439. g_bug_bFirstCommand = true;
  440. ProcessCommand( "pause ; status" );
  441. }
  442. else
  443. {
  444. ProcessCommand( "status" );
  445. }
  446. }
  447. }
  448. //-----------------------------------------------------------------------------
  449. // BugDlg_GetDataFileBase
  450. //
  451. //-----------------------------------------------------------------------------
  452. void BugDlg_GetDataFileBase( char const *suffix, bool bLocalPath, char *buf, int bufsize )
  453. {
  454. char filepath[MAX_PATH];
  455. char filename[MAX_PATH];
  456. struct tm t;
  457. time_t ltime;
  458. time( &ltime );
  459. tm *pTime = localtime( &ltime );
  460. memcpy( &t, pTime, sizeof( t ) );
  461. char who[128];
  462. strncpy( who, suffix, sizeof( who ) );
  463. _strlwr( who );
  464. if ( bLocalPath )
  465. {
  466. // add a qualified local path
  467. // used as a gathering store before uploading to server
  468. strcpy( filepath, g_localPath );
  469. Sys_AddFileSeperator( filepath, sizeof( filepath ) );
  470. strcat( filepath, "bug/" );
  471. Sys_NormalizePath( filepath, false );
  472. Sys_CreatePath( filepath );
  473. }
  474. else
  475. {
  476. filepath[0] = '\0';
  477. }
  478. sprintf( filename, "%i_%02i_%02i_%s", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, who );
  479. V_snprintf( buf, bufsize, "%s%s", filepath, filename );
  480. }
  481. //-----------------------------------------------------------------------------
  482. // BugDlg_CheckSubmit
  483. //
  484. //-----------------------------------------------------------------------------
  485. bool BugDlg_CheckSubmit( HWND hWnd )
  486. {
  487. bool bEnableSubmit = false;
  488. if ( g_Games[g_bug_GameType].bUsesSystem1 )
  489. {
  490. if ( g_bug_szTitle[0] &&
  491. g_bug_szDescription[0] &&
  492. g_bug_szSeverity[0] &&
  493. g_bug_szOwner[0] &&
  494. g_bug_szReportType[0] &&
  495. g_bug_szPriority[0] &&
  496. g_bug_szArea[0] )
  497. {
  498. bEnableSubmit = true;
  499. }
  500. }
  501. else
  502. {
  503. if ( g_bug_szTitle[0] &&
  504. g_bug_szDescription[0] &&
  505. g_bug_szSeverity[0] &&
  506. g_bug_szOwner[0] &&
  507. g_bug_szArea[0] &&
  508. g_bug_szMapNumber[0] )
  509. {
  510. bEnableSubmit = true;
  511. }
  512. }
  513. EnableWindow( GetDlgItem( hWnd, IDC_BUG_SUBMIT ), bEnableSubmit );
  514. return bEnableSubmit;
  515. }
  516. //-----------------------------------------------------------------------------
  517. // BugDlg_GetChanges
  518. //
  519. //-----------------------------------------------------------------------------
  520. bool BugDlg_GetChanges( HWND hWnd )
  521. {
  522. int curSel;
  523. // title
  524. GetDlgItemText( hWnd, IDC_BUG_TITLE, g_bug_szTitle, sizeof( g_bug_szTitle ) );
  525. // description
  526. GetDlgItemText( hWnd, IDC_BUG_DESCRIPTION, g_bug_szDescription, sizeof( g_bug_szDescription ) );
  527. // owner
  528. curSel = SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_GETCURSEL, 0, 0 );
  529. if ( curSel == CB_ERR )
  530. {
  531. g_bug_szOwner[0] = '\0';
  532. }
  533. else
  534. {
  535. strncpy( g_bug_szOwner, g_bug_pReporter->GetDisplayName( curSel ), sizeof( g_bug_szOwner ) );
  536. g_bug_szOwner[sizeof( g_bug_szOwner )-1] = '\0';
  537. if ( V_stristr( g_bug_szOwner, "unassigned" ) )
  538. {
  539. g_bug_szOwner[0] = '\0';
  540. }
  541. }
  542. // severity
  543. curSel = SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_GETCURSEL, 0, 0 );
  544. if ( curSel == CB_ERR )
  545. {
  546. g_bug_szSeverity[0] = '\0';
  547. }
  548. else
  549. {
  550. V_strncpy( g_bug_szSeverity, g_bug_pReporter->GetSeverity( curSel ), sizeof( g_bug_szSeverity ) );
  551. }
  552. // report type
  553. curSel = SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_GETCURSEL, 0, 0 );
  554. if ( curSel == CB_ERR )
  555. {
  556. g_bug_szReportType[0] = '\0';
  557. }
  558. else
  559. {
  560. V_strncpy( g_bug_szReportType, g_bug_pReporter->GetReportType( curSel ), sizeof( g_bug_szReportType ) );
  561. }
  562. // priority
  563. curSel = SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_GETCURSEL, 0, 0 );
  564. if ( curSel == CB_ERR )
  565. {
  566. g_bug_szPriority[0] = '\0';
  567. }
  568. else
  569. {
  570. V_strncpy( g_bug_szPriority, g_bug_pReporter->GetPriority( curSel ), sizeof( g_bug_szPriority ) );
  571. }
  572. // area
  573. curSel = SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_GETCURSEL, 0, 0 );
  574. int areaIndex = 0;
  575. if ( curSel == CB_ERR )
  576. {
  577. g_bug_szArea[0] = '\0';
  578. }
  579. else
  580. {
  581. V_strncpy( g_bug_szArea, g_bug_pReporter->GetArea( curSel ), sizeof( g_bug_szArea ) );
  582. areaIndex = curSel;
  583. }
  584. if ( !g_Games[g_bug_GameType].bUsesSystem1 )
  585. {
  586. // map number
  587. curSel = SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_GETCURSEL, 0, 0 );
  588. if ( curSel == CB_ERR )
  589. {
  590. g_bug_szMapNumber[0] = '\0';
  591. }
  592. else
  593. {
  594. V_strncpy( g_bug_szMapNumber, g_bug_pReporter->GetLevel( areaIndex, curSel ), sizeof( g_bug_szMapNumber ) );
  595. }
  596. }
  597. g_bug_bCompressScreenshot = ( IsDlgButtonChecked( hWnd, IDC_BUG_COMPRESS_SCREENSHOT ) != 0 );
  598. BugDlg_CheckSubmit( hWnd );
  599. // success
  600. return true;
  601. }
  602. //-----------------------------------------------------------------------------
  603. // BugDlg_UpdateReporter
  604. //
  605. //-----------------------------------------------------------------------------
  606. bool BugDlg_UpdateReporter( HWND hWnd )
  607. {
  608. // game
  609. int newGameType;
  610. int curSel = SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_GETCURSEL, 0, 0 );
  611. if ( curSel == CB_ERR )
  612. {
  613. newGameType = 0;
  614. }
  615. else
  616. {
  617. newGameType = curSel;
  618. }
  619. return BugReporter_SelectReporter( g_Games[newGameType].pGameName );
  620. }
  621. //-----------------------------------------------------------------------------
  622. // BugDlg_Populate
  623. //
  624. //-----------------------------------------------------------------------------
  625. void BugDlg_Populate( HWND hWnd )
  626. {
  627. int i;
  628. int count;
  629. int curSel;
  630. g_bug_bActive = false;
  631. // title
  632. SendDlgItemMessage( hWnd, IDC_BUG_TITLE, EM_LIMITTEXT, sizeof( g_bug_szTitle )-1, 0 );
  633. SetDlgItemText( hWnd, IDC_BUG_TITLE, g_bug_szTitle );
  634. // description
  635. SendDlgItemMessage( hWnd, IDC_BUG_DESCRIPTION, EM_LIMITTEXT, sizeof( g_bug_szDescription )-1, 0 );
  636. SetDlgItemText( hWnd, IDC_BUG_DESCRIPTION, g_bug_szDescription );
  637. // submitter
  638. SetDlgItemText( hWnd, IDC_BUG_SUBMITTER_LABEL, g_bug_pReporter->GetUserName_Display() );
  639. // owner
  640. SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_RESETCONTENT, 0, 0 );
  641. count = g_bug_pReporter->GetDisplayNameCount();
  642. for ( i = 0; i < count; i++ )
  643. {
  644. SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetDisplayName( i ) );
  645. }
  646. if ( count )
  647. {
  648. curSel = SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szOwner );
  649. if ( curSel != CB_ERR )
  650. {
  651. SendDlgItemMessage( hWnd, IDC_BUG_OWNER, CB_SETCURSEL, curSel, 0 );
  652. }
  653. }
  654. // severity
  655. SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_RESETCONTENT, 0, 0 );
  656. count = g_bug_pReporter->GetSeverityCount();
  657. for ( i = 0; i < count; i++ )
  658. {
  659. SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetSeverity( i ) );
  660. }
  661. if ( count )
  662. {
  663. curSel = SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szSeverity );
  664. if ( curSel != CB_ERR )
  665. {
  666. SendDlgItemMessage( hWnd, IDC_BUG_SEVERITY, CB_SETCURSEL, curSel, 0 );
  667. }
  668. }
  669. // report type
  670. SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_RESETCONTENT, 0, 0 );
  671. EnableWindow( GetDlgItem( hWnd, IDC_BUG_REPORTTYPE ), g_Games[g_bug_GameType].bUsesSystem1 );
  672. if ( g_Games[g_bug_GameType].bUsesSystem1 )
  673. {
  674. count = g_bug_pReporter->GetReportTypeCount();
  675. for ( i = 0; i < count; i++ )
  676. {
  677. SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetReportType( i ) );
  678. }
  679. if ( count )
  680. {
  681. curSel = SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szReportType );
  682. if ( curSel != CB_ERR )
  683. {
  684. SendDlgItemMessage( hWnd, IDC_BUG_REPORTTYPE, CB_SETCURSEL, curSel, 0 );
  685. }
  686. }
  687. }
  688. // priority
  689. SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_RESETCONTENT, 0, 0 );
  690. EnableWindow( GetDlgItem( hWnd, IDC_BUG_PRIORITY ), g_Games[g_bug_GameType].bUsesSystem1 );
  691. if ( g_Games[g_bug_GameType].bUsesSystem1 )
  692. {
  693. count = g_bug_pReporter->GetPriorityCount();
  694. for ( i = 0; i < count; i++ )
  695. {
  696. SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetPriority( i ) );
  697. }
  698. if ( count )
  699. {
  700. curSel = SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szPriority );
  701. if ( curSel != CB_ERR )
  702. {
  703. SendDlgItemMessage( hWnd, IDC_BUG_PRIORITY, CB_SETCURSEL, curSel, 0 );
  704. }
  705. }
  706. }
  707. // area
  708. SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_RESETCONTENT, 0, 0 );
  709. count = g_bug_pReporter->GetAreaCount();
  710. int areaIndex = 0;
  711. for ( i = 0; i < count; i++ )
  712. {
  713. SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetArea( i ) );
  714. }
  715. if ( count )
  716. {
  717. curSel = SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szArea );
  718. if ( curSel != CB_ERR )
  719. {
  720. SendDlgItemMessage( hWnd, IDC_BUG_AREA, CB_SETCURSEL, curSel, 0 );
  721. areaIndex = curSel;
  722. }
  723. }
  724. // map name or number
  725. SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_RESETCONTENT, 0, 0 );
  726. EnableWindow( GetDlgItem( hWnd, IDC_BUG_MAPNUMBER ), g_Games[g_bug_GameType].bUsesSystem1 == false );
  727. if ( !g_Games[g_bug_GameType].bUsesSystem1 )
  728. {
  729. // new system has map names
  730. count = g_bug_pReporter->GetLevelCount( areaIndex );
  731. for ( i = 0; i < count; i++ )
  732. {
  733. SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_bug_pReporter->GetLevel( areaIndex, i ) );
  734. }
  735. }
  736. if ( count )
  737. {
  738. curSel = SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szMapNumber );
  739. if ( curSel != CB_ERR )
  740. {
  741. SendDlgItemMessage( hWnd, IDC_BUG_MAPNUMBER, CB_SETCURSEL, curSel, 0 );
  742. }
  743. }
  744. // game
  745. SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_RESETCONTENT, 0, 0 );
  746. count = ARRAYSIZE( g_Games );
  747. for ( i = 0; i < count; i++ )
  748. {
  749. SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)g_Games[i].pFriendlyName );
  750. }
  751. if ( count )
  752. {
  753. curSel = SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_Games[g_bug_GameType].pFriendlyName );
  754. if ( curSel != CB_ERR )
  755. {
  756. SendDlgItemMessage( hWnd, IDC_BUG_GAME, CB_SETCURSEL, curSel, 0 );
  757. }
  758. }
  759. CheckDlgButton( hWnd, IDC_BUG_COMPRESS_SCREENSHOT, g_bug_bCompressScreenshot ? BST_CHECKED : BST_UNCHECKED );
  760. SetDlgItemText( hWnd, IDC_BUG_TAKESHOT_LABEL, g_bug_szScreenshot );
  761. SetDlgItemText( hWnd, IDC_BUG_SAVEGAME_LABEL, g_bug_szSavegame );
  762. SetDlgItemText( hWnd, IDC_BUG_INCLUDEBSP_LABEL, g_bug_szBSPName );
  763. SetDlgItemText( hWnd, IDC_BUG_INCLUDEVMF_LABEL, "" );
  764. EnableWindow( GetDlgItem( hWnd, IDC_BUG_TAKESHOT ), g_connectedToApp );
  765. EnableWindow( GetDlgItem( hWnd, IDC_BUG_INCLUDEVMF ), false );
  766. EnableWindow( GetDlgItem( hWnd, IDC_BUG_UPDATE ), g_connectedToApp );
  767. BugDlg_GetAppData( hWnd );
  768. BugDlg_CheckSubmit( hWnd );
  769. g_bug_bActive = true;
  770. }
  771. //-----------------------------------------------------------------------------
  772. // BugDlg_TakeScreenshot
  773. //
  774. //-----------------------------------------------------------------------------
  775. void BugDlg_TakeScreenshot( HWND hWnd )
  776. {
  777. char buff[1024];
  778. SetDlgItemText( hWnd, IDC_BUG_TAKESHOT_LABEL, "Working..." );
  779. BugDlg_GetDataFileBase( g_bug_pReporter->GetUserName(), true, g_bug_szScreenshot, sizeof( g_bug_szScreenshot ) );
  780. strcat( g_bug_szScreenshot, ".bmp" );
  781. // remove local version
  782. unlink( g_bug_szScreenshot );
  783. sprintf( buff, "*screenshot \"%s\"", g_bug_szScreenshot );
  784. if ( !ProcessCommand( buff ) )
  785. {
  786. g_bug_szScreenshot[0] = '\0';
  787. }
  788. SetDlgItemText( hWnd, IDC_BUG_TAKESHOT_LABEL, g_bug_szScreenshot );
  789. }
  790. //-----------------------------------------------------------------------------
  791. // BugDlg_SaveGame
  792. //
  793. //-----------------------------------------------------------------------------
  794. void BugDlg_SaveGame( HWND hWnd )
  795. {
  796. char buff[1024];
  797. char savename[MAX_PATH];
  798. char remoteFile[MAX_PATH];
  799. if ( !g_bug_mapInfo.savePath[0] )
  800. {
  801. return;
  802. }
  803. SetDlgItemText( hWnd, IDC_BUG_SAVEGAME_LABEL, "Working..." );
  804. BugDlg_GetDataFileBase( g_bug_pReporter->GetUserName(), true, g_bug_szSavegame, sizeof( g_bug_szSavegame ) );
  805. Sys_StripPath( g_bug_szSavegame, savename, sizeof( savename ) );
  806. strcat( g_bug_szSavegame, ".360.sav" );
  807. sprintf( remoteFile, "%s\\%s.360.sav", g_bug_mapInfo.savePath, savename );
  808. // delete file locally
  809. unlink( g_bug_szSavegame );
  810. // delete file remotely
  811. DmDeleteFile( remoteFile, false );
  812. // save, and wait to ensure async completes
  813. sprintf( buff, "save \"%s\" notmostrecent wait", savename );
  814. if ( !ProcessCommand( buff ) )
  815. {
  816. // failed
  817. g_bug_szSavegame[0] = '\0';
  818. }
  819. else
  820. {
  821. DM_FILE_ATTRIBUTES fileAttributes;
  822. for (int i=0; i<5; i++)
  823. {
  824. // wait for the save file to appear
  825. HRESULT hr = DmGetFileAttributes( remoteFile, &fileAttributes );
  826. if ( hr == XBDM_NOERR )
  827. break;
  828. // wait for it
  829. Sleep( 1000 );
  830. }
  831. HRESULT hr = DmReceiveFile( g_bug_szSavegame, remoteFile );
  832. if ( hr != XBDM_NOERR )
  833. {
  834. // failed
  835. g_bug_szSavegame[0] = '\0';
  836. }
  837. }
  838. SetDlgItemText( hWnd, IDC_BUG_SAVEGAME_LABEL, g_bug_szSavegame );
  839. }
  840. //-----------------------------------------------------------------------------
  841. // BugDlg_IncludeBSP
  842. //
  843. //-----------------------------------------------------------------------------
  844. void BugDlg_IncludeBSP( HWND hWnd )
  845. {
  846. if ( !g_bug_mapInfo.mapPath[0] )
  847. {
  848. return;
  849. }
  850. SetDlgItemText( hWnd, IDC_BUG_INCLUDEBSP_LABEL, "Working..." );
  851. BugDlg_GetDataFileBase( g_bug_pReporter->GetUserName(), true, g_bug_szBSPName, sizeof( g_bug_szBSPName ) );
  852. strcat( g_bug_szBSPName, ".360.bsp" );
  853. // remove local version
  854. unlink( g_bug_szBSPName );
  855. // get the file locally
  856. HRESULT hr = DmReceiveFile( g_bug_szBSPName, g_bug_mapInfo.mapPath );
  857. if ( hr != XBDM_NOERR )
  858. {
  859. // failed
  860. g_bug_szBSPName[0] = '\0';
  861. }
  862. SetDlgItemText( hWnd, IDC_BUG_INCLUDEBSP_LABEL, g_bug_szBSPName );
  863. }
  864. //-----------------------------------------------------------------------------
  865. // BugDlg_ResetAndPopulate
  866. //
  867. //-----------------------------------------------------------------------------
  868. void BugDlg_ResetAndPopulate( HWND hWnd, bool bFullReset = true )
  869. {
  870. // reset all fields
  871. if ( bFullReset )
  872. {
  873. g_bug_szTitle[0] = '\0';
  874. g_bug_szDescription[0] = '\0';
  875. }
  876. g_bug_szOwner[0] = '\0';
  877. g_bug_szSeverity[0] = '\0';
  878. g_bug_szReportType[0] = '\0';
  879. g_bug_szPriority[0] = '\0';
  880. g_bug_szMapNumber[0] = '\0';
  881. if ( bFullReset )
  882. {
  883. g_bug_szScreenshot[0] = '\0';
  884. g_bug_szSavegame[0] = '\0';
  885. g_bug_szBSPName[0] = '\0';
  886. }
  887. g_bug_bCompressScreenshot = true;
  888. memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) );
  889. // populate with reset fields
  890. BugDlg_Populate( hWnd );
  891. }
  892. //-----------------------------------------------------------------------------
  893. // BugDlg_Setup
  894. //
  895. //-----------------------------------------------------------------------------
  896. void BugDlg_Setup( HWND hWnd )
  897. {
  898. g_bug_hWnd = hWnd;
  899. // clear stale data from app
  900. g_bug_bFirstCommand = false;
  901. memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) );
  902. // always reset these fields
  903. g_bug_szTitle[0] = '\0';
  904. g_bug_szDescription[0] = '\0';
  905. g_bug_szScreenshot[0] = '\0';
  906. g_bug_szSavegame[0] = '\0';
  907. g_bug_szBSPName[0] = '\0';
  908. g_bug_bCompressScreenshot = true;
  909. memset( &g_bug_mapInfo, 0, sizeof( g_bug_mapInfo ) );
  910. BugDlg_Populate( hWnd );
  911. }
  912. //-----------------------------------------------------------------------------
  913. // BugDlg_UploadFile
  914. //
  915. //-----------------------------------------------------------------------------
  916. bool BugDlg_UploadFile( char const *pLocalName, char const *pRemoteName, bool bDeleteLocal )
  917. {
  918. FILE *fp;
  919. int len;
  920. void *pLocalData;
  921. ConsoleWindowPrintf( BUG_COLOR, "Uploading %s to %s\n", pLocalName, pRemoteName );
  922. len = Sys_LoadFile( pLocalName, &pLocalData );
  923. if ( !pLocalData || !len )
  924. {
  925. ConsoleWindowPrintf( XBX_CLR_RED, "UploadFile: Unable to open local path '%s'\n", pLocalName );
  926. return false;
  927. }
  928. Sys_CreatePath( pRemoteName );
  929. fp = fopen( pRemoteName, "wb" );
  930. if ( !fp )
  931. {
  932. ConsoleWindowPrintf( XBX_CLR_RED, "UploadFile: Unable to open remote path '%s'\n", pRemoteName );
  933. Sys_Free( pLocalData );
  934. return false;
  935. }
  936. fwrite( pLocalData, len, 1, fp );
  937. fclose( fp );
  938. Sys_Free( pLocalData );
  939. if ( bDeleteLocal )
  940. {
  941. unlink( pLocalName );
  942. }
  943. return true;
  944. }
  945. //-----------------------------------------------------------------------------
  946. // BugDlg_UploadBugSubmission
  947. //
  948. // Expects fully qualified source paths
  949. //-----------------------------------------------------------------------------
  950. bool BugDlg_UploadBugSubmission( int bugID, char const *pSavefile, char const *pScreenshot, char const *pBspFile, char const *pVmfFile )
  951. {
  952. char szFilename[MAX_PATH];
  953. char szLocalfile[MAX_PATH];
  954. char szRemotefile[MAX_PATH];
  955. bool bSuccess = true;
  956. if ( pSavefile && pSavefile[0] )
  957. {
  958. V_snprintf( szLocalfile, sizeof( szLocalfile ), "%s", pSavefile );
  959. Sys_StripPath( pSavefile, szFilename, sizeof( szFilename ) );
  960. V_snprintf( szRemotefile, sizeof( szRemotefile ), "%s/%s", GetSubmissionURL( bugID ), szFilename );
  961. Sys_NormalizePath( szLocalfile, false );
  962. Sys_NormalizePath( szRemotefile, false );
  963. if ( !BugDlg_UploadFile( szLocalfile, szRemotefile, false ) )
  964. {
  965. bSuccess = false;
  966. }
  967. }
  968. if ( pScreenshot && pScreenshot[0] )
  969. {
  970. V_snprintf( szLocalfile, sizeof( szLocalfile ), "%s", pScreenshot );
  971. Sys_StripPath( pScreenshot, szFilename, sizeof( szFilename ) );
  972. V_snprintf( szRemotefile, sizeof( szRemotefile ), "%s/%s", GetSubmissionURL( bugID ), szFilename );
  973. Sys_NormalizePath( szLocalfile, false );
  974. Sys_NormalizePath( szRemotefile, false );
  975. if ( !BugDlg_UploadFile( szLocalfile, szRemotefile, true ) )
  976. {
  977. bSuccess = false;
  978. }
  979. }
  980. if ( pBspFile && pBspFile[0] )
  981. {
  982. V_snprintf( szLocalfile, sizeof( szLocalfile ), "%s", pBspFile );
  983. Sys_StripPath( pBspFile, szFilename, sizeof( szFilename ) );
  984. V_snprintf( szRemotefile, sizeof( szRemotefile ), "%s/%s", GetSubmissionURL( bugID ), szFilename );
  985. Sys_NormalizePath( szLocalfile, false );
  986. Sys_NormalizePath( szRemotefile, false );
  987. if ( !BugDlg_UploadFile( szLocalfile, szRemotefile, true ) )
  988. {
  989. bSuccess = false;
  990. }
  991. }
  992. return bSuccess;
  993. }
  994. //-----------------------------------------------------------------------------
  995. // BugDlg_Submit
  996. //
  997. //-----------------------------------------------------------------------------
  998. bool BugDlg_Submit( HWND hWnd )
  999. {
  1000. char title[1024];
  1001. char miscInfo[1024];
  1002. char basename[MAX_PATH];
  1003. char filename[MAX_PATH];
  1004. char positionName[MAX_PATH];
  1005. char orientationName[MAX_PATH];
  1006. char buildName[MAX_PATH];
  1007. char mapName[MAX_PATH];
  1008. bool bSuccess = false;
  1009. sprintf( positionName, "%f %f %f", g_bug_mapInfo.position[0], g_bug_mapInfo.position[1], g_bug_mapInfo.position[2] );
  1010. SetDlgItemText( g_bug_hWnd, IDC_BUG_POSITION_LABEL, positionName );
  1011. sprintf( orientationName, "%f %f %f", g_bug_mapInfo.angle[0], g_bug_mapInfo.angle[1], g_bug_mapInfo.angle[2] );
  1012. SetDlgItemText( g_bug_hWnd, IDC_BUG_ORIENTATION_LABEL, orientationName );
  1013. sprintf( buildName, "%d", g_bug_mapInfo.build );
  1014. SetDlgItemText( g_bug_hWnd, IDC_BUG_BUILD_LABEL, buildName );
  1015. V_FileBase( g_bug_mapInfo.mapPath, mapName, sizeof( mapName ) );
  1016. char *pExtension = V_stristr( mapName, ".bsp" );
  1017. if ( pExtension )
  1018. {
  1019. *pExtension = '\0';
  1020. }
  1021. pExtension = V_stristr( mapName, ".360" );
  1022. if ( pExtension )
  1023. {
  1024. *pExtension = '\0';
  1025. }
  1026. V_snprintf( miscInfo, sizeof( miscInfo ), "skill %d", g_bug_mapInfo.skill );
  1027. // Stuff bug data files up to server
  1028. g_bug_pReporter->StartNewBugReport();
  1029. g_bug_pReporter->SetOwner( g_bug_pReporter->GetUserNameForDisplayName( g_bug_szOwner ) );
  1030. g_bug_pReporter->SetSubmitter( NULL );
  1031. if ( mapName[0] )
  1032. V_snprintf( title, sizeof( title ), "%s: %s", mapName, g_bug_szTitle );
  1033. else
  1034. V_snprintf( title, sizeof( title ), "%s", g_bug_szTitle );
  1035. g_bug_pReporter->SetTitle( title );
  1036. g_bug_pReporter->SetDescription( g_bug_szDescription );
  1037. g_bug_pReporter->SetLevel( mapName );
  1038. g_bug_pReporter->SetPosition( positionName );
  1039. g_bug_pReporter->SetOrientation( orientationName );
  1040. g_bug_pReporter->SetBuildNumber( buildName );
  1041. g_bug_pReporter->SetSeverity( g_bug_szSeverity );
  1042. g_bug_pReporter->SetPriority( g_bug_szPriority );
  1043. g_bug_pReporter->SetArea( g_bug_szArea );
  1044. g_bug_pReporter->SetMapNumber( g_bug_szMapNumber );
  1045. g_bug_pReporter->SetReportType( g_bug_szReportType );
  1046. g_bug_pReporter->SetMiscInfo( miscInfo );
  1047. g_bug_pReporter->SetDriverInfo( "" );
  1048. g_bug_pReporter->SetExeName( "" );
  1049. g_bug_pReporter->SetGameDirectory( "" );
  1050. g_bug_pReporter->SetRAM( 0 );
  1051. g_bug_pReporter->SetCPU( 0 );
  1052. g_bug_pReporter->SetProcessor( "" );
  1053. g_bug_pReporter->SetDXVersion( 0, 0, 0, 0 );
  1054. g_bug_pReporter->SetOSVersion( "" );
  1055. g_bug_pReporter->ResetIncludedFiles();
  1056. g_bug_pReporter->SetZipAttachmentName( "" );
  1057. if ( g_bug_szScreenshot[0] )
  1058. {
  1059. if ( g_bug_bCompressScreenshot )
  1060. {
  1061. BugDlg_CompressScreenshot();
  1062. }
  1063. // strip the fully qualified path into filename only
  1064. Sys_StripPath( g_bug_szScreenshot, basename, sizeof( basename ) );
  1065. V_snprintf( filename, sizeof( filename ), "%s/BugId/%s", GetRepositoryURL(), basename );
  1066. Sys_NormalizePath( filename, false );
  1067. g_bug_pReporter->SetScreenShot( filename );
  1068. }
  1069. if ( g_bug_szSavegame[0] )
  1070. {
  1071. // strip the fully qualified path into filename only
  1072. Sys_StripPath( g_bug_szSavegame, basename, sizeof( basename ) );
  1073. V_snprintf( filename, sizeof( filename ), "%s/BugId/%s", GetRepositoryURL(), basename );
  1074. Sys_NormalizePath( filename, false );
  1075. g_bug_pReporter->SetSaveGame( filename );
  1076. }
  1077. if ( g_bug_szBSPName[0] )
  1078. {
  1079. // strip the fully qualified path into filename only
  1080. Sys_StripPath( g_bug_szBSPName, basename, sizeof( basename ) );
  1081. V_snprintf( filename, sizeof( filename ), "%s/BugId/%s", GetRepositoryURL(), basename );
  1082. Sys_NormalizePath( filename, false );
  1083. g_bug_pReporter->SetBSPName( filename );
  1084. }
  1085. int bugID = -1;
  1086. bSuccess = g_bug_pReporter->CommitBugReport( bugID );
  1087. if ( bSuccess )
  1088. {
  1089. if ( !BugDlg_UploadBugSubmission( bugID, g_bug_szSavegame, g_bug_szScreenshot, g_bug_szBSPName, NULL ) )
  1090. {
  1091. Sys_MessageBox( BUG_ERRORTITLE, "Unable to upload files to bug repository!\n" );
  1092. bSuccess = false;
  1093. }
  1094. }
  1095. else
  1096. {
  1097. Sys_MessageBox( BUG_ERRORTITLE, "Unable to post bug report to database!\n" );
  1098. }
  1099. if ( bSuccess )
  1100. {
  1101. if ( g_Games[g_bug_GameType].bUsesSystem1 )
  1102. {
  1103. ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: PVCS submission succeeded for bug! (%d)\n", bugID );
  1104. }
  1105. else
  1106. {
  1107. ConsoleWindowPrintf( BUG_COLOR, "Bug Reporter: BugBait submission succeeded for bug!\n" );
  1108. }
  1109. }
  1110. else
  1111. {
  1112. ConsoleWindowPrintf( XBX_CLR_RED, "Bug Reporter: Submission failed\n" );
  1113. }
  1114. return bSuccess;
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // BugDlg_Proc
  1118. //
  1119. //-----------------------------------------------------------------------------
  1120. BOOL CALLBACK BugDlg_Proc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
  1121. {
  1122. switch ( message )
  1123. {
  1124. case WM_INITDIALOG:
  1125. BugDlg_Setup( hwnd );
  1126. return ( TRUE );
  1127. case WM_COMMAND:
  1128. switch ( LOWORD( wParam ) )
  1129. {
  1130. case IDC_BUG_TAKESHOT:
  1131. BugDlg_TakeScreenshot( hwnd );
  1132. break;
  1133. case IDC_BUG_SAVEGAME:
  1134. BugDlg_SaveGame( hwnd );
  1135. break;
  1136. case IDC_BUG_INCLUDEBSP:
  1137. BugDlg_IncludeBSP( hwnd );
  1138. break;
  1139. case IDC_BUG_INCLUDEVMF:
  1140. // not implemented, no reason to
  1141. break;
  1142. case IDC_BUG_CLEARFORM:
  1143. BugDlg_ResetAndPopulate( hwnd );
  1144. return TRUE;
  1145. case IDC_BUG_UPDATE:
  1146. BugDlg_GetAppData( hwnd );
  1147. return TRUE;
  1148. case IDC_BUG_OWNER:
  1149. case IDC_BUG_SEVERITY:
  1150. case IDC_BUG_REPORTTYPE:
  1151. case IDC_BUG_PRIORITY:
  1152. case IDC_BUG_AREA:
  1153. case IDC_BUG_MAPNUMBER:
  1154. if ( g_bug_bActive && HIWORD( wParam ) == CBN_CLOSEUP )
  1155. {
  1156. BugDlg_GetChanges( hwnd );
  1157. return TRUE;
  1158. }
  1159. break;
  1160. case IDC_BUG_GAME:
  1161. if ( HIWORD( wParam ) == CBN_CLOSEUP )
  1162. {
  1163. if ( BugDlg_UpdateReporter( hwnd ) )
  1164. {
  1165. // reporter changed, clear critical parts of form
  1166. BugDlg_ResetAndPopulate( hwnd, false );
  1167. }
  1168. return TRUE;
  1169. }
  1170. break;
  1171. case IDC_BUG_TITLE:
  1172. case IDC_BUG_DESCRIPTION:
  1173. if ( g_bug_bActive && HIWORD( wParam ) == EN_CHANGE )
  1174. {
  1175. BugDlg_GetChanges( hwnd );
  1176. return TRUE;
  1177. }
  1178. break;
  1179. case IDC_BUG_COMPRESS_SCREENSHOT:
  1180. BugDlg_GetChanges( hwnd );
  1181. return TRUE;
  1182. case IDC_BUG_SUBMIT:
  1183. if ( !BugDlg_Submit( hwnd ) )
  1184. break;
  1185. // fall through
  1186. case IDCANCEL:
  1187. case IDC_CANCEL:
  1188. if ( g_connectedToApp && g_bug_bFirstCommand )
  1189. {
  1190. ProcessCommand( "unpause" );
  1191. }
  1192. EndDialog( hwnd, wParam );
  1193. return ( TRUE );
  1194. }
  1195. break;
  1196. }
  1197. return ( FALSE );
  1198. }
  1199. //-----------------------------------------------------------------------------
  1200. // BugDlg_SaveConfig
  1201. //
  1202. //-----------------------------------------------------------------------------
  1203. void BugDlg_SaveConfig()
  1204. {
  1205. Sys_SetRegistryString( "bug_owner", g_bug_szOwner );
  1206. Sys_SetRegistryString( "bug_severity", g_bug_szSeverity );
  1207. Sys_SetRegistryString( "bug_reporttype", g_bug_szReportType );
  1208. Sys_SetRegistryString( "bug_priority", g_bug_szPriority );
  1209. Sys_SetRegistryInteger( "bug_gametype", g_bug_GameType );
  1210. }
  1211. //-----------------------------------------------------------------------------
  1212. // BugDlg_LoadConfig
  1213. //
  1214. //-----------------------------------------------------------------------------
  1215. void BugDlg_LoadConfig()
  1216. {
  1217. // get our config
  1218. Sys_GetRegistryString( "bug_owner", g_bug_szOwner, "", sizeof( g_bug_szOwner ) );
  1219. Sys_GetRegistryString( "bug_severity", g_bug_szSeverity, "", sizeof( g_bug_szSeverity ) );
  1220. Sys_GetRegistryString( "bug_reporttype", g_bug_szReportType, "", sizeof( g_bug_szReportType ) );
  1221. Sys_GetRegistryString( "bug_priority", g_bug_szPriority, "", sizeof( g_bug_szPriority ) );
  1222. Sys_GetRegistryInteger( "bug_gametype", 0, g_bug_GameType );
  1223. // start with expected reporter
  1224. BugReporter_SelectReporter( g_Games[g_bug_GameType].pGameName );
  1225. }
  1226. //-----------------------------------------------------------------------------
  1227. // BugDlg_Open
  1228. //
  1229. //-----------------------------------------------------------------------------
  1230. void BugDlg_Open( void )
  1231. {
  1232. int result;
  1233. // need access to bug databases via DLLs
  1234. if ( !BugReporter_GetInterfaces() )
  1235. {
  1236. return;
  1237. }
  1238. BugDlg_LoadConfig();
  1239. result = DialogBox( g_hInstance, MAKEINTRESOURCE( IDD_BUG ), g_hDlgMain, ( DLGPROC )BugDlg_Proc );
  1240. if ( LOWORD( result ) == IDC_BUG_SUBMIT )
  1241. {
  1242. BugDlg_SaveConfig();
  1243. }
  1244. g_bug_hWnd = NULL;
  1245. }
  1246. //-----------------------------------------------------------------------------
  1247. // BugDlg_Init
  1248. //
  1249. //-----------------------------------------------------------------------------
  1250. bool BugDlg_Init()
  1251. {
  1252. return true;
  1253. }
  1254. //-----------------------------------------------------------------------------
  1255. // rc_MapInfo
  1256. //
  1257. // Sent from application with bug dialog info
  1258. //-----------------------------------------------------------------------------
  1259. int rc_MapInfo( char* commandPtr )
  1260. {
  1261. char* cmdToken;
  1262. int errCode;
  1263. int infoAddr;
  1264. int retVal;
  1265. int retAddr;
  1266. char buff[128];
  1267. // success
  1268. errCode = 0;
  1269. // get address of data
  1270. cmdToken = GetToken( &commandPtr );
  1271. if ( !cmdToken[0] )
  1272. goto cleanUp;
  1273. sscanf( cmdToken, "%x", &infoAddr );
  1274. // get retAddr
  1275. cmdToken = GetToken( &commandPtr );
  1276. if ( !cmdToken[0] )
  1277. goto cleanUp;
  1278. sscanf( cmdToken, "%x", &retAddr );
  1279. // get the caller's info data
  1280. DmGetMemory( ( void* )infoAddr, sizeof( xrMapInfo_t ), &g_bug_mapInfo, NULL );
  1281. // swap the structure
  1282. BigFloat( &g_bug_mapInfo.position[0], &g_bug_mapInfo.position[0] );
  1283. BigFloat( &g_bug_mapInfo.position[1], &g_bug_mapInfo.position[1] );
  1284. BigFloat( &g_bug_mapInfo.position[2], &g_bug_mapInfo.position[2] );
  1285. BigFloat( &g_bug_mapInfo.angle[0], &g_bug_mapInfo.angle[0] );
  1286. BigFloat( &g_bug_mapInfo.angle[1], &g_bug_mapInfo.angle[1] );
  1287. BigFloat( &g_bug_mapInfo.angle[2], &g_bug_mapInfo.angle[2] );
  1288. g_bug_mapInfo.build = BigDWord( g_bug_mapInfo.build );
  1289. g_bug_mapInfo.skill = BigDWord( g_bug_mapInfo.skill );
  1290. Sys_NormalizePath( g_bug_mapInfo.savePath, false );
  1291. Sys_NormalizePath( g_bug_mapInfo.mapPath, false );
  1292. if ( g_bug_hWnd )
  1293. {
  1294. if ( g_bug_mapInfo.mapPath[0] )
  1295. {
  1296. Sys_StripPath( g_bug_mapInfo.mapPath, buff, sizeof( buff ) );
  1297. SetDlgItemText( g_bug_hWnd, IDC_BUG_MAP_LABEL, buff );
  1298. if ( !g_Games[g_bug_GameType].bUsesSystem1 )
  1299. {
  1300. char *pExtension = V_stristr( buff, ".bsp" );
  1301. if ( pExtension )
  1302. {
  1303. *pExtension = '\0';
  1304. }
  1305. pExtension = V_stristr( buff, ".360" );
  1306. if ( pExtension )
  1307. {
  1308. *pExtension = '\0';
  1309. }
  1310. V_strncpy( g_bug_szMapNumber, buff, sizeof( g_bug_szMapNumber ) );
  1311. int curSel = SendDlgItemMessage( g_bug_hWnd, IDC_BUG_MAPNUMBER, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)(LPCSTR)g_bug_szMapNumber );
  1312. if ( curSel == CB_ERR )
  1313. curSel = 0;
  1314. SendDlgItemMessage( g_bug_hWnd, IDC_BUG_MAPNUMBER, CB_SETCURSEL, curSel, 0 );
  1315. }
  1316. sprintf( buff, "%.2f %.2f %.2f", g_bug_mapInfo.position[0], g_bug_mapInfo.position[1], g_bug_mapInfo.position[2] );
  1317. SetDlgItemText( g_bug_hWnd, IDC_BUG_POSITION_LABEL, buff );
  1318. sprintf( buff, "%.2f %.2f %.2f", g_bug_mapInfo.angle[0], g_bug_mapInfo.angle[1], g_bug_mapInfo.angle[2] );
  1319. SetDlgItemText( g_bug_hWnd, IDC_BUG_ORIENTATION_LABEL, buff );
  1320. }
  1321. else
  1322. {
  1323. SetDlgItemText( g_bug_hWnd, IDC_BUG_MAP_LABEL, "" );
  1324. SetDlgItemText( g_bug_hWnd, IDC_BUG_POSITION_LABEL, "" );
  1325. SetDlgItemText( g_bug_hWnd, IDC_BUG_ORIENTATION_LABEL, "" );
  1326. }
  1327. sprintf( buff, "%d", g_bug_mapInfo.build );
  1328. SetDlgItemText( g_bug_hWnd, IDC_BUG_BUILD_LABEL, buff );
  1329. EnableWindow( GetDlgItem( g_bug_hWnd, IDC_BUG_SAVEGAME ), g_bug_mapInfo.savePath[0] != '\0' && g_bug_mapInfo.mapPath[0] != '\0' );
  1330. EnableWindow( GetDlgItem( g_bug_hWnd, IDC_BUG_INCLUDEBSP ), g_bug_mapInfo.mapPath[0] != '\0' );
  1331. }
  1332. // return the result
  1333. retVal = 0;
  1334. int xboxRetVal = BigDWord( retVal );
  1335. DmSetMemory( ( void* )retAddr, sizeof( int ), &xboxRetVal, NULL );
  1336. DebugCommand( "0x%8.8x = MapInfo( 0x%8.8x )\n", retVal, infoAddr );
  1337. cleanUp:
  1338. return errCode;
  1339. }