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.

1179 lines
28 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #define PROTECTED_THINGS_DISABLE
  7. #undef PROTECT_FILEIO_FUNCTIONS
  8. #undef fopen
  9. #include <windows.h>
  10. #include "basetypes.h"
  11. #include "utlvector.h"
  12. #include "utlsymbol.h"
  13. #include "utldict.h"
  14. #include "utlbuffer.h"
  15. #include "bugreporter/bugreporter.h"
  16. #include "trktool.h"
  17. #include "filesystem_tools.h"
  18. #include "KeyValues.h"
  19. #define SCR_TYPE 1
  20. #define TRACKER_SETTINGS "resource/bugreporter.res"
  21. #define TRACKER_LOGIN "cfg/bugreporter_login.res"
  22. #define DEFAULT_DBMS "tracker"
  23. #define DEFAULT_PROJECT "Half-Life 2"
  24. #define DEFAULT_USERNAME ""
  25. #define DEFAULT_PASSWORD DEFAULT_USERNAME
  26. IBaseFileSystem *g_pFileSystem = NULL;
  27. class CBug
  28. {
  29. public:
  30. CBug()
  31. {
  32. Clear();
  33. }
  34. void Clear()
  35. {
  36. Q_memset( title, 0, sizeof( title ) );
  37. Q_memset( desc, 0, sizeof( desc ) );
  38. Q_memset( submitter, 0, sizeof( submitter ) );
  39. Q_memset( owner, 0, sizeof( owner ) );
  40. Q_memset( severity, 0, sizeof( severity ) );
  41. Q_memset( priority, 0, sizeof( priority ) );
  42. Q_memset( area, 0, sizeof( area ) );
  43. Q_memset( mapnumber, 0, sizeof( mapnumber) );
  44. Q_memset( reporttype, 0, sizeof( reporttype ) );
  45. Q_memset( level, 0, sizeof( level ) );
  46. Q_memset( build, 0, sizeof( build ) );
  47. Q_memset( position, 0, sizeof( position ) );
  48. Q_memset( orientation, 0, sizeof( orientation ) );
  49. Q_memset( screenshot_unc, 0, sizeof( screenshot_unc ) );
  50. Q_memset( savegame_unc, 0, sizeof( savegame_unc ) );
  51. Q_memset( bsp_unc, 0, sizeof( bsp_unc ) );
  52. Q_memset( vmf_unc, 0, sizeof( vmf_unc ) );
  53. Q_memset( driverinfo, 0, sizeof( driverinfo ) );
  54. Q_memset( misc, 0, sizeof( misc ) );
  55. includedfiles.Purge();
  56. }
  57. char title[ 256 ];
  58. char desc[ 8192 ];
  59. char owner[ 256 ];
  60. char submitter[ 256 ];
  61. char severity[ 256 ];
  62. char priority[ 256 ];
  63. char area[ 256 ];
  64. char mapnumber[ 256 ];
  65. char reporttype[ 256 ];
  66. char level[ 256 ];
  67. char build[ 256 ];
  68. char position[ 256 ];
  69. char orientation[ 256 ];
  70. char screenshot_unc[ 256 ];
  71. char savegame_unc[ 256 ];
  72. char bsp_unc[ 256 ];
  73. char vmf_unc[ 256 ];
  74. char driverinfo[ 2048 ];
  75. char misc[ 1024 ];
  76. struct incfile
  77. {
  78. char name[ 256 ];
  79. };
  80. CUtlVector< incfile > includedfiles;
  81. };
  82. class CBugReporter : public IBugReporter
  83. {
  84. public:
  85. CBugReporter();
  86. virtual ~CBugReporter();
  87. // Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  88. virtual bool Init( CreateInterfaceFn engineFactory );
  89. virtual void Shutdown();
  90. virtual bool IsPublicUI() { return false; }
  91. virtual char const *GetUserName();
  92. virtual char const *GetUserName_Display();
  93. virtual int GetNameCount();
  94. virtual char const *GetName( int index );
  95. virtual int GetDisplayNameCount();
  96. virtual char const *GetDisplayName( int index );
  97. virtual char const *GetDisplayNameForUserName( char const *username );
  98. virtual char const *GetUserNameForDisplayName( char const *display );
  99. virtual int GetSeverityCount();
  100. virtual char const *GetSeverity( int index );
  101. virtual int GetPriorityCount();
  102. virtual char const *GetPriority( int index );
  103. virtual int GetAreaCount();
  104. virtual char const *GetArea( int index );
  105. virtual int GetAreaMapCount();
  106. virtual char const *GetAreaMap( int index );
  107. virtual int GetMapNumberCount();
  108. virtual char const *GetMapNumber( int index );
  109. virtual int GetReportTypeCount();
  110. virtual char const *GetReportType( int index );
  111. virtual char const *GetRepositoryURL( void ) { return NULL; }
  112. virtual char const *GetSubmissionURL( void ) { return NULL; }
  113. virtual int GetLevelCount(int area) { return 0; }
  114. virtual char const *GetLevel(int area, int index ) { return ""; }
  115. // Submission API
  116. virtual void StartNewBugReport();
  117. virtual void CancelNewBugReport();
  118. virtual bool CommitBugReport( int& bugSubmissionId );
  119. virtual void SetTitle( char const *title );
  120. virtual void SetDescription( char const *description );
  121. // NULL for current user
  122. virtual void SetSubmitter( char const *username = 0 );
  123. virtual void SetOwner( char const *username );
  124. virtual void SetSeverity( char const *severity );
  125. virtual void SetPriority( char const *priority );
  126. virtual void SetArea( char const *area );
  127. virtual void SetMapNumber ( char const *mapnumber );
  128. virtual void SetReportType( char const *reporttype );
  129. virtual void SetLevel( char const *levelnamne );
  130. virtual void SetPosition( char const *position );
  131. virtual void SetOrientation( char const *pitch_yaw_roll );
  132. virtual void SetBuildNumber( char const *build_num );
  133. virtual void SetScreenShot( char const *screenshot_unc_address );
  134. virtual void SetSaveGame( char const *savegame_unc_address );
  135. virtual void SetBSPName( char const *bsp_unc_address );
  136. virtual void SetVMFName( char const *vmf_unc_address );
  137. virtual void AddIncludedFile( char const *filename );
  138. virtual void ResetIncludedFiles();
  139. virtual void SetZipAttachmentName( char const *zipfilename ) {} // only used by public bug reporter
  140. virtual void SetDriverInfo( char const *info );
  141. virtual void SetMiscInfo( char const *info );
  142. // These are stubbed here, but are used by the public version...
  143. virtual void SetCSERAddress( const struct netadr_s& adr ) {}
  144. virtual void SetExeName( char const *exename ) {}
  145. virtual void SetGameDirectory( char const *gamedir ) {}
  146. virtual void SetRAM( int ram ) {}
  147. virtual void SetCPU( int cpu ) {}
  148. virtual void SetProcessor( char const *processor ) {}
  149. virtual void SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device ) {}
  150. virtual void SetOSVersion( char const *osversion ) {}
  151. virtual void SetSteamUserID( void *steamid, int idsize ) {};
  152. private:
  153. void ReportError(TRK_UINT rc, char const *func, char const *msg );
  154. TRK_UINT Login(TRK_HANDLE* pTrkHandle);
  155. bool PopulateLists();
  156. bool PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list );
  157. void SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src );
  158. CUtlSymbolTable m_BugStrings;
  159. CUtlVector< CUtlSymbol > m_Severity;
  160. CUtlVector< CUtlSymbol > m_Names;
  161. CUtlVector< CUtlSymbol > m_SortedDisplayNames;
  162. CUtlDict< CUtlSymbol, int > m_InternalNameMapping;
  163. CUtlVector< CUtlSymbol > m_Priority;
  164. CUtlVector< CUtlSymbol > m_Area;
  165. CUtlVector< CUtlSymbol > m_AreaMap;
  166. CUtlVector< CUtlSymbol > m_MapNumber;
  167. CUtlVector< CUtlSymbol > m_ReportType;
  168. TRK_HANDLE trkHandle;
  169. TRK_RECORD_HANDLE trkRecHandle;
  170. CUtlSymbol m_UserName;
  171. CBug *m_pBug;
  172. };
  173. CBugReporter::CBugReporter()
  174. {
  175. m_pBug = NULL;
  176. trkHandle = (TRK_HANDLE)0;
  177. trkRecHandle = (TRK_RECORD_HANDLE)0;
  178. }
  179. CBugReporter::~CBugReporter()
  180. {
  181. m_BugStrings.RemoveAll();
  182. m_Severity.Purge();
  183. m_Names.Purge();
  184. m_SortedDisplayNames.Purge();
  185. m_InternalNameMapping.Purge();
  186. m_Priority.Purge();
  187. m_Area.Purge();
  188. m_MapNumber.Purge();
  189. m_ReportType.Purge();
  190. delete m_pBug;
  191. }
  192. struct TRKELookup
  193. {
  194. unsigned int id;
  195. char const *str;
  196. };
  197. #define TRKERROR( id ) { id, #id }
  198. static TRKELookup g_Lookup[] =
  199. {
  200. TRKERROR( TRK_SUCCESS ),
  201. TRKERROR( TRK_E_VERSION_MISMATCH ),
  202. TRKERROR( TRK_E_OUT_OF_MEMORY ),
  203. TRKERROR( TRK_E_BAD_HANDLE ),
  204. TRKERROR( TRK_E_BAD_INPUT_POINTER ),
  205. TRKERROR( TRK_E_BAD_INPUT_VALUE ),
  206. TRKERROR( TRK_E_DATA_TRUNCATED ),
  207. TRKERROR( TRK_E_NO_MORE_DATA ),
  208. TRKERROR( TRK_E_LIST_NOT_INITIALIZED ),
  209. TRKERROR( TRK_E_END_OF_LIST ),
  210. TRKERROR( TRK_E_NOT_LOGGED_IN ),
  211. TRKERROR( TRK_E_SERVER_NOT_PREPARED ),
  212. TRKERROR( TRK_E_BAD_DATABASE_VERSION ),
  213. TRKERROR( TRK_E_UNABLE_TO_CONNECT ),
  214. TRKERROR( TRK_E_UNABLE_TO_DISCONNECT ),
  215. TRKERROR( TRK_E_UNABLE_TO_START_TIMER ),
  216. TRKERROR( TRK_E_NO_DATA_SOURCES ),
  217. TRKERROR( TRK_E_NO_PROJECTS ),
  218. TRKERROR( TRK_E_WRITE_FAILED ),
  219. TRKERROR( TRK_E_PERMISSION_DENIED ),
  220. TRKERROR( TRK_E_SET_FIELD_DENIED ),
  221. TRKERROR( TRK_E_ITEM_NOT_FOUND ),
  222. TRKERROR( TRK_E_CANNOT_ACCESS_DATABASE ),
  223. TRKERROR( TRK_E_CANNOT_ACCESS_QUERY ),
  224. TRKERROR( TRK_E_CANNOT_ACCESS_INTRAY ),
  225. TRKERROR( TRK_E_CANNOT_OPEN_FILE ),
  226. TRKERROR( TRK_E_INVALID_DBMS_TYPE ),
  227. TRKERROR( TRK_E_INVALID_RECORD_TYPE ),
  228. TRKERROR( TRK_E_INVALID_FIELD ),
  229. TRKERROR( TRK_E_INVALID_CHOICE ),
  230. TRKERROR( TRK_E_INVALID_USER ),
  231. TRKERROR( TRK_E_INVALID_SUBMITTER ),
  232. TRKERROR( TRK_E_INVALID_OWNER ),
  233. TRKERROR( TRK_E_INVALID_DATE ),
  234. TRKERROR( TRK_E_INVALID_STORED_QUERY ),
  235. TRKERROR( TRK_E_INVALID_MODE ),
  236. TRKERROR( TRK_E_INVALID_MESSAGE ),
  237. TRKERROR( TRK_E_VALUE_OUT_OF_RANGE ),
  238. TRKERROR( TRK_E_WRONG_FIELD_TYPE ),
  239. TRKERROR( TRK_E_NO_CURRENT_RECORD ),
  240. TRKERROR( TRK_E_NO_CURRENT_NOTE ),
  241. TRKERROR( TRK_E_NO_CURRENT_ATTACHED_FILE ),
  242. TRKERROR( TRK_E_NO_CURRENT_ASSOCIATION ),
  243. TRKERROR( TRK_E_NO_RECORD_BEGIN ),
  244. TRKERROR( TRK_E_NO_MODULE ),
  245. TRKERROR( TRK_E_USER_CANCELLED ),
  246. TRKERROR( TRK_E_SEMAPHORE_TIMEOUT ),
  247. TRKERROR( TRK_E_SEMAPHORE_ERROR ),
  248. TRKERROR( TRK_E_INVALID_SERVER_NAME ),
  249. TRKERROR( TRK_E_NOT_LICENSED )
  250. };
  251. void CBugReporter::ReportError(TRK_UINT rc, char const *func, char const *msg )
  252. {
  253. if ( rc != TRK_SUCCESS )
  254. {
  255. switch (rc)
  256. {
  257. case TRK_E_ITEM_NOT_FOUND:
  258. Msg( "%s %s was not found!\n", func, msg );
  259. break;
  260. case TRK_E_INVALID_FIELD:
  261. Msg( "%s %s Invalid field!\n", func, msg );
  262. break;
  263. default:
  264. int i = 0;
  265. for ( i; i < ARRAYSIZE( g_Lookup ) ; ++i )
  266. {
  267. if ( g_Lookup[ i ].id == rc )
  268. {
  269. Msg( "%s returned %i - %s!\n", func, rc, g_Lookup[ i ].str );
  270. break;
  271. }
  272. }
  273. if ( i >= ARRAYSIZE( g_Lookup ) )
  274. {
  275. Msg( "%s returned %i - %s!\n", func, rc, "???" );
  276. }
  277. break;
  278. }
  279. }
  280. }
  281. TRK_UINT CBugReporter::Login(TRK_HANDLE* pTrkHandle)
  282. {
  283. char dbms[50] = DEFAULT_DBMS;
  284. char proj[50] = DEFAULT_PROJECT;
  285. char username[ 50 ];
  286. char password[ 50 ];
  287. GetPrivateProfileStringA(
  288. "login",
  289. "userid1",
  290. DEFAULT_USERNAME, // default
  291. username,
  292. sizeof( username ),
  293. "PVCSTRK.ini" );
  294. if ( !Q_stricmp( username, DEFAULT_USERNAME) || !Q_stricmp( username, "BELMAPNTKY" ) ) // if userid1 didn't have a valid name in it try userid0
  295. {
  296. GetPrivateProfileStringA(
  297. "login",
  298. "userid0",
  299. DEFAULT_USERNAME, // default
  300. username,
  301. sizeof( username ),
  302. "PVCSTRK.ini" );
  303. }
  304. Q_strncpy( password, username, sizeof( password ) );
  305. if ( g_pFileSystem )
  306. {
  307. KeyValues *kv = new KeyValues( "tracker_login" );
  308. Assert( kv );
  309. if ( kv )
  310. {
  311. if ( kv->LoadFromFile( g_pFileSystem, TRACKER_SETTINGS ) )
  312. {
  313. Q_strncpy( dbms, kv->GetString( "database_server", DEFAULT_DBMS ), sizeof( dbms ) );
  314. Q_strncpy( proj, kv->GetString( "project_name", DEFAULT_PROJECT ), sizeof( proj ) );
  315. }
  316. kv->Clear();
  317. // Load optional login info
  318. if ( g_pFileSystem->FileExists( TRACKER_LOGIN, "GAME" ) )
  319. {
  320. if ( kv->LoadFromFile( g_pFileSystem, TRACKER_LOGIN ) )
  321. {
  322. Q_strncpy( username, kv->GetString( "username", username ), sizeof( username ) );
  323. Q_strncpy( password, kv->GetString( "password", password ), sizeof( password ) );
  324. }
  325. }
  326. kv->deleteThis();
  327. }
  328. }
  329. bool maybeNoPVCSInstalled = false;
  330. // We still don't know the username. . try to get it from the environment
  331. if( username[0] == '\0' )
  332. {
  333. if( getenv( "username" ) )
  334. {
  335. Q_strncpy( username, getenv( "username" ), sizeof( username ) );
  336. maybeNoPVCSInstalled = true;
  337. }
  338. }
  339. m_UserName = m_BugStrings.AddString( username );
  340. TRK_UINT rc = TrkProjectLogin(*pTrkHandle,
  341. username,
  342. password,
  343. proj,
  344. NULL,
  345. NULL,
  346. NULL,
  347. NULL,
  348. TRK_USE_INI_FILE_DBMS_LOGIN);
  349. if (rc != TRK_SUCCESS)
  350. {
  351. rc = TrkProjectLogin(*pTrkHandle,
  352. username,
  353. "",
  354. proj,
  355. NULL,
  356. NULL,
  357. NULL,
  358. NULL,
  359. TRK_USE_INI_FILE_DBMS_LOGIN);
  360. if (rc != TRK_SUCCESS)
  361. {
  362. if ( maybeNoPVCSInstalled )
  363. {
  364. Msg("Bug reporter failed: Make sure you have PVCS installed and that you have logged into it successfully at least once.\n");
  365. }
  366. else
  367. {
  368. Msg("Bug reporter init failed: Your tracker password must be your user name or blank.\n");
  369. }
  370. return rc;
  371. }
  372. }
  373. TrkGetLoginDBMSName(*pTrkHandle, sizeof(dbms), dbms );
  374. TrkGetLoginProjectName(*pTrkHandle, sizeof(proj), proj );
  375. Msg( "Project: %s\n", proj );
  376. Msg( "Server: %s\n", dbms );
  377. return rc;
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  381. // Output : Returns true on success, false on failure.
  382. //-----------------------------------------------------------------------------
  383. bool CBugReporter::Init( CreateInterfaceFn engineFactory )
  384. {
  385. if ( engineFactory )
  386. {
  387. g_pFileSystem = (IFileSystem *)engineFactory( FILESYSTEM_INTERFACE_VERSION, NULL );
  388. if ( !g_pFileSystem )
  389. {
  390. AssertMsg( 0, "Failed to create/get IFileSystem" );
  391. return false;
  392. }
  393. }
  394. TRK_UINT rc;
  395. rc = TrkHandleAlloc( TRK_VERSION_ID, &trkHandle);
  396. if ( rc != TRK_SUCCESS )
  397. {
  398. ReportError(rc, "TrkHandleAlloc", "Failed to Allocate Tracker Handle!");
  399. return false;
  400. }
  401. // Login to default project out of INI file.
  402. rc = Login( &trkHandle );
  403. if (rc != TRK_SUCCESS)
  404. {
  405. return false;
  406. }
  407. rc = TrkRecordHandleAlloc(trkHandle, &trkRecHandle);
  408. if (rc != TRK_SUCCESS)
  409. {
  410. ReportError(rc, "TrkRecordHandleAlloc",
  411. "Failed to Allocate Tracker Record Handle!");
  412. return false;
  413. }
  414. PopulateLists();
  415. return true;
  416. }
  417. void CBugReporter::Shutdown()
  418. {
  419. TRK_UINT rc;
  420. if ( trkRecHandle )
  421. {
  422. rc = TrkRecordHandleFree(&trkRecHandle);
  423. if (rc != TRK_SUCCESS)
  424. {
  425. ReportError(rc, "TrkRecordHandleFree", "Failed to Free Tracker Record Handle!");
  426. }
  427. }
  428. if ( trkHandle )
  429. {
  430. rc = TrkProjectLogout(trkHandle);
  431. if (rc != TRK_SUCCESS)
  432. {
  433. ReportError(rc, "TrkProjectLogout", "Failed to Logout of Project!");
  434. }
  435. else
  436. {
  437. rc = TrkHandleFree(&trkHandle);
  438. if (rc != TRK_SUCCESS)
  439. {
  440. ReportError(rc, "TrkHandleFree", "Failed to Free Tracker Handle!");
  441. }
  442. }
  443. }
  444. }
  445. char const *CBugReporter::GetUserName()
  446. {
  447. return m_BugStrings.String( m_UserName );
  448. }
  449. char const *CBugReporter::GetUserName_Display()
  450. {
  451. return GetDisplayNameForUserName( GetUserName() );
  452. }
  453. int CBugReporter::GetNameCount()
  454. {
  455. return m_Names.Count();
  456. }
  457. char const *CBugReporter::GetName( int index )
  458. {
  459. if ( index < 0 || index >= m_Names.Count() )
  460. return "<<Invalid>>";
  461. return m_BugStrings.String( m_Names[ index ] );
  462. }
  463. int CBugReporter::GetDisplayNameCount()
  464. {
  465. return m_SortedDisplayNames.Count();
  466. }
  467. char const *CBugReporter::GetDisplayName( int index )
  468. {
  469. if ( index < 0 || index >= (int)m_SortedDisplayNames.Count() )
  470. return "<<Invalid>>";
  471. return m_BugStrings.String( m_SortedDisplayNames[ index ] );
  472. }
  473. char const *CBugReporter::GetDisplayNameForUserName( char const *username )
  474. {
  475. int c = GetDisplayNameCount();
  476. for ( int i = 0; i < c ; i++ )
  477. {
  478. CUtlSymbol sym = m_InternalNameMapping[ i ];
  479. char const *testname = m_BugStrings.String( sym );
  480. if ( !Q_stricmp( testname, username ) )
  481. {
  482. return m_InternalNameMapping.GetElementName( i );
  483. }
  484. }
  485. return "<<Invalid>>";
  486. }
  487. char const *CBugReporter::GetUserNameForDisplayName( char const *display )
  488. {
  489. int idx = m_InternalNameMapping.Find( display );
  490. if ( idx == m_InternalNameMapping.InvalidIndex() )
  491. return "<<Invalid>>";
  492. CUtlSymbol sym;
  493. sym = m_InternalNameMapping[ idx ];
  494. return m_BugStrings.String( sym );
  495. }
  496. int CBugReporter::GetSeverityCount()
  497. {
  498. return m_Severity.Count() ;
  499. }
  500. char const *CBugReporter::GetSeverity( int index )
  501. {
  502. if ( index < 0 || index >= m_Severity.Count() )
  503. return "<<Invalid>>";
  504. return m_BugStrings.String( m_Severity[ index ] );
  505. }
  506. int CBugReporter::GetPriorityCount()
  507. {
  508. return m_Priority.Count();
  509. }
  510. char const *CBugReporter::GetPriority( int index )
  511. {
  512. if ( index < 0 || index >= m_Priority.Count() )
  513. return "<<Invalid>>";
  514. return m_BugStrings.String( m_Priority[ index ] );
  515. }
  516. int CBugReporter::GetAreaCount()
  517. {
  518. return m_Area.Count();
  519. }
  520. char const *CBugReporter::GetArea( int index )
  521. {
  522. if ( index < 0 || index >= m_Area.Count() )
  523. return "<<Invalid>>";
  524. return m_BugStrings.String( m_Area[ index ] );
  525. }
  526. int CBugReporter::GetAreaMapCount()
  527. {
  528. return m_AreaMap.Count();
  529. }
  530. char const *CBugReporter::GetAreaMap( int index )
  531. {
  532. if ( index < 0 || index >= m_AreaMap.Count() )
  533. return "<<Invalid>>";
  534. return m_BugStrings.String( m_AreaMap[ index ] );
  535. }
  536. int CBugReporter::GetMapNumberCount()
  537. {
  538. return m_MapNumber.Count();
  539. }
  540. char const *CBugReporter::GetMapNumber( int index )
  541. {
  542. if ( index < 0 || index >= m_MapNumber.Count() )
  543. return "<<Invalid>>";
  544. return m_BugStrings.String( m_MapNumber[ index ] );
  545. }
  546. int CBugReporter::GetReportTypeCount()
  547. {
  548. return m_ReportType.Count();
  549. }
  550. char const *CBugReporter::GetReportType( int index )
  551. {
  552. if ( index < 0 || index >= m_ReportType.Count() )
  553. return "<<Invalid>>";
  554. return m_BugStrings.String( m_ReportType[ index ] );
  555. }
  556. void CBugReporter::StartNewBugReport()
  557. {
  558. if ( !m_pBug )
  559. {
  560. m_pBug = new CBug();
  561. }
  562. else
  563. {
  564. m_pBug->Clear();
  565. }
  566. }
  567. void CBugReporter::CancelNewBugReport()
  568. {
  569. if ( !m_pBug )
  570. return;
  571. m_pBug->Clear();
  572. }
  573. void CBugReporter::SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src )
  574. {
  575. out[ 0 ] = 0;
  576. char *dest = out;
  577. src.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  578. char const *replace = "\\BugId\\";
  579. int replace_len = Q_strlen( replace );
  580. for ( int pos = 0; pos <= src.TellPut() && ( ( dest - out ) < outlen ); )
  581. {
  582. char const *str = ( char const * )src.PeekGet( pos );
  583. if ( !Q_strnicmp( str, replace, replace_len ) )
  584. {
  585. *dest++ = '\\';
  586. char num[ 32 ];
  587. Q_snprintf( num, sizeof( num ), "%i", bugid );
  588. char *pnum = num;
  589. while ( *pnum )
  590. {
  591. *dest++ = *pnum++;
  592. }
  593. *dest++ = '\\';
  594. pos += replace_len;
  595. continue;
  596. }
  597. *dest++ = *str;
  598. ++pos;
  599. }
  600. *dest = 0;
  601. }
  602. bool CBugReporter::CommitBugReport( int& bugSubmissionId )
  603. {
  604. bugSubmissionId = -1;
  605. if ( !m_pBug )
  606. return false;
  607. TRK_UINT rc = 0;
  608. rc = TrkNewRecordBegin( trkRecHandle, SCR_TYPE );
  609. if ( rc != TRK_SUCCESS )
  610. {
  611. ReportError(rc, "TrkNewRecordBegin",
  612. "Failed to TrkNewRecordBegin!");
  613. return false;
  614. }
  615. // Populate fields
  616. rc = TrkSetStringFieldValue( trkRecHandle,
  617. "Title",
  618. m_pBug->title );
  619. if ( rc != TRK_SUCCESS )
  620. {
  621. ReportError(rc, "TrkSetStringFieldValue",
  622. "Failed to add title!");
  623. return false;
  624. }
  625. rc = TrkSetStringFieldValue( trkRecHandle,
  626. "Submitter",
  627. m_pBug->submitter );
  628. if ( rc != TRK_SUCCESS )
  629. {
  630. ReportError(rc, "TrkSetStringFieldValue",
  631. "Failed to set submitter!");
  632. return false;
  633. }
  634. rc = TrkSetStringFieldValue( trkRecHandle,
  635. "Owner",
  636. m_pBug->owner );
  637. if ( rc != TRK_SUCCESS )
  638. {
  639. ReportError(rc, "TrkSetStringFieldValue",
  640. "Failed to set owner!");
  641. return false;
  642. }
  643. rc = TrkSetStringFieldValue( trkRecHandle,
  644. "Severity",
  645. m_pBug->severity );
  646. if ( rc != TRK_SUCCESS )
  647. {
  648. ReportError(rc, "TrkSetStringFieldValue",
  649. "Failed to set severity!");
  650. //return false;
  651. }
  652. rc = TrkSetStringFieldValue( trkRecHandle,
  653. "Report Type",
  654. m_pBug->reporttype );
  655. if ( rc != TRK_SUCCESS )
  656. {
  657. ReportError(rc, "TrkSetStringFieldValue",
  658. "Failed to set report type!");
  659. //return false;
  660. }
  661. rc = TrkSetStringFieldValue( trkRecHandle,
  662. "Priority",
  663. m_pBug->priority );
  664. if ( rc != TRK_SUCCESS )
  665. {
  666. ReportError(rc, "TrkSetStringFieldValue",
  667. "Failed to set priority!");
  668. //return false;
  669. }
  670. rc = TrkSetStringFieldValue( trkRecHandle,
  671. "Area",
  672. m_pBug->area );
  673. if ( rc != TRK_SUCCESS )
  674. {
  675. ReportError(rc, "TrkSetStringFieldValue",
  676. "Failed to set area!");
  677. //return false;
  678. }
  679. rc = TrkSetStringFieldValue( trkRecHandle,
  680. "Map Number",
  681. m_pBug->mapnumber );
  682. if ( rc != TRK_SUCCESS )
  683. {
  684. ReportError(rc, "TrkSetStringFieldValue",
  685. "Failed to set map area!");
  686. //return false;
  687. }
  688. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  689. buf.Printf( "%s\n\n", m_pBug->desc );
  690. buf.Printf( "level: %s\nbuild: %s\nposition: setpos %s; setang %s\n",
  691. m_pBug->level,
  692. m_pBug->build,
  693. m_pBug->position,
  694. m_pBug->orientation );
  695. if ( m_pBug->screenshot_unc[ 0 ] )
  696. {
  697. buf.Printf( "screenshot: %s\n", m_pBug->screenshot_unc );
  698. }
  699. if ( m_pBug->savegame_unc[ 0 ] )
  700. {
  701. buf.Printf( "savegame: %s\n", m_pBug->savegame_unc );
  702. }
  703. if ( m_pBug->bsp_unc[ 0 ] )
  704. {
  705. buf.Printf( "bsp: %s\n", m_pBug->bsp_unc );
  706. }
  707. if ( m_pBug->vmf_unc[ 0 ] )
  708. {
  709. buf.Printf( "vmf: %s\n", m_pBug->vmf_unc );
  710. }
  711. if ( m_pBug->includedfiles.Count() > 0 )
  712. {
  713. int c = m_pBug->includedfiles.Count();
  714. for ( int i = 0 ; i < c; ++i )
  715. {
  716. buf.Printf( "include: %s\n", m_pBug->includedfiles[ i ].name );
  717. }
  718. }
  719. if ( m_pBug->driverinfo[ 0 ] )
  720. {
  721. buf.Printf( "%s\n", m_pBug->driverinfo );
  722. }
  723. if ( m_pBug->misc[ 0 ] )
  724. {
  725. buf.Printf( "%s\n", m_pBug->misc );
  726. }
  727. buf.PutChar( 0 );
  728. rc = TrkSetDescriptionData( trkRecHandle,
  729. buf.TellPut(),
  730. (const char * )buf.Base(),
  731. 0 );
  732. if ( rc != TRK_SUCCESS )
  733. {
  734. ReportError(rc, "TrkSetDescriptionData",
  735. "Failed to set description data!");
  736. return false;
  737. }
  738. TRK_TRANSACTION_ID id;
  739. rc = TrkNewRecordCommit( trkRecHandle, &id );
  740. if ( rc != TRK_SUCCESS )
  741. {
  742. ReportError(rc, "TrkNewRecordCommit",
  743. "Failed to TrkNewRecordCommit!");
  744. return false;
  745. }
  746. TRK_UINT bugId;
  747. rc = TrkGetNumericFieldValue( trkRecHandle, "Id", &bugId );
  748. if ( rc != TRK_SUCCESS )
  749. {
  750. ReportError(rc, "TrkGetNumericFieldValue",
  751. "Failed to TrkGetNumericFieldValue for bug Id #!");
  752. }
  753. else
  754. {
  755. bugSubmissionId = (int)bugId;
  756. }
  757. rc = TrkGetSingleRecord( trkRecHandle, bugId, SCR_TYPE );
  758. if ( rc != TRK_SUCCESS )
  759. {
  760. ReportError( rc, "TrkGetSingleRecord",
  761. "Failed to open bug id for update" );
  762. return false;
  763. }
  764. rc = TrkUpdateRecordBegin( trkRecHandle );
  765. if ( rc != TRK_SUCCESS )
  766. {
  767. ReportError( rc, "TrkUpdateRecordBegin",
  768. "Failed to open bug id for update" );
  769. return false;
  770. }
  771. else
  772. {
  773. int textbuflen = 2 * buf.TellPut() + 1;
  774. char *textbuf = new char [ textbuflen ];
  775. Q_memset( textbuf, 0, textbuflen );
  776. SubstituteBugId( (int)bugId, textbuf, textbuflen, buf );
  777. // Update the description with the substituted text!!!
  778. rc = TrkSetDescriptionData( trkRecHandle,
  779. Q_strlen( textbuf ) + 1,
  780. (const char * )textbuf,
  781. 0 );
  782. delete[] textbuf;
  783. if ( rc != TRK_SUCCESS )
  784. {
  785. ReportError(rc, "TrkSetDescriptionData(update)",
  786. "Failed to set description data!");
  787. return false;
  788. }
  789. rc = TrkUpdateRecordCommit( trkRecHandle, &id );
  790. if ( rc != TRK_SUCCESS )
  791. {
  792. ReportError(rc, "TrkUpdateRecordCommit",
  793. "Failed to TrkUpdateRecordCommit for bug Id #!");
  794. return false;
  795. }
  796. }
  797. m_pBug->Clear();
  798. return true;
  799. }
  800. void CBugReporter::SetTitle( char const *title )
  801. {
  802. Assert( m_pBug );
  803. Q_strncpy( m_pBug->title, title, sizeof( m_pBug->title ) );
  804. }
  805. void CBugReporter::SetDescription( char const *description )
  806. {
  807. Assert( m_pBug );
  808. Q_strncpy( m_pBug->desc, description, sizeof( m_pBug->desc ) );
  809. }
  810. void CBugReporter::SetSubmitter( char const *username /*= 0*/ )
  811. {
  812. if ( !username )
  813. {
  814. username = GetUserName();
  815. }
  816. Assert( m_pBug );
  817. Q_strncpy( m_pBug->submitter, username, sizeof( m_pBug->submitter ) );
  818. }
  819. void CBugReporter::SetOwner( char const *username )
  820. {
  821. Assert( m_pBug );
  822. Q_strncpy( m_pBug->owner, username, sizeof( m_pBug->owner ) );
  823. }
  824. void CBugReporter::SetSeverity( char const *severity )
  825. {
  826. Assert( m_pBug );
  827. Q_strncpy( m_pBug->severity, severity, sizeof( m_pBug->severity ) );
  828. }
  829. void CBugReporter::SetPriority( char const *priority )
  830. {
  831. Assert( m_pBug );
  832. Q_strncpy( m_pBug->priority, priority, sizeof( m_pBug->priority ) );
  833. }
  834. void CBugReporter::SetArea( char const *area )
  835. {
  836. Assert( m_pBug );
  837. Q_strncpy( m_pBug->area, area, sizeof( m_pBug->area ) );
  838. }
  839. void CBugReporter::SetMapNumber( char const *mapnumber )
  840. {
  841. Assert( m_pBug);
  842. Q_strncpy( m_pBug->mapnumber, mapnumber, sizeof( m_pBug->mapnumber ) );
  843. }
  844. void CBugReporter::SetReportType( char const *reporttype )
  845. {
  846. Assert( m_pBug );
  847. Q_strncpy( m_pBug->reporttype, reporttype, sizeof( m_pBug->reporttype ) );
  848. }
  849. void CBugReporter::SetLevel( char const *levelnamne )
  850. {
  851. Assert( m_pBug );
  852. Q_strncpy( m_pBug->level, levelnamne, sizeof( m_pBug->level ) );
  853. }
  854. void CBugReporter::SetDriverInfo( char const *info )
  855. {
  856. Assert( m_pBug );
  857. Q_strncpy( m_pBug->driverinfo, info, sizeof( m_pBug->driverinfo ) );
  858. }
  859. void CBugReporter::SetMiscInfo( char const *info )
  860. {
  861. Assert( m_pBug );
  862. Q_strncpy( m_pBug->misc, info, sizeof( m_pBug->misc ) );
  863. }
  864. void CBugReporter::SetPosition( char const *position )
  865. {
  866. Assert( m_pBug );
  867. Q_strncpy( m_pBug->position, position, sizeof( m_pBug->position ) );
  868. }
  869. void CBugReporter::SetOrientation( char const *pitch_yaw_roll )
  870. {
  871. Assert( m_pBug );
  872. Q_strncpy( m_pBug->orientation, pitch_yaw_roll, sizeof( m_pBug->orientation ) );
  873. }
  874. void CBugReporter::SetBuildNumber( char const *build_num )
  875. {
  876. Assert( m_pBug );
  877. Q_strncpy( m_pBug->build, build_num, sizeof( m_pBug->build ) );
  878. }
  879. void CBugReporter::SetScreenShot( char const *screenshot_unc_address )
  880. {
  881. Assert( m_pBug );
  882. Q_strncpy( m_pBug->screenshot_unc, screenshot_unc_address, sizeof( m_pBug->screenshot_unc ) );
  883. }
  884. void CBugReporter::SetSaveGame( char const *savegame_unc_address )
  885. {
  886. Assert( m_pBug );
  887. Q_strncpy( m_pBug->savegame_unc, savegame_unc_address, sizeof( m_pBug->savegame_unc ) );
  888. }
  889. void CBugReporter::SetBSPName( char const *bsp_unc_address )
  890. {
  891. Assert( m_pBug );
  892. Q_strncpy( m_pBug->bsp_unc, bsp_unc_address, sizeof( m_pBug->bsp_unc ) );
  893. }
  894. void CBugReporter::SetVMFName( char const *vmf_unc_address )
  895. {
  896. Assert( m_pBug );
  897. Q_strncpy( m_pBug->vmf_unc, vmf_unc_address, sizeof( m_pBug->vmf_unc ) );
  898. }
  899. void CBugReporter::AddIncludedFile( char const *filename )
  900. {
  901. CBug::incfile includedfile;
  902. Q_strncpy( includedfile.name, filename, sizeof( includedfile.name ) );
  903. m_pBug->includedfiles.AddToTail( includedfile );
  904. }
  905. void CBugReporter::ResetIncludedFiles()
  906. {
  907. m_pBug->includedfiles.Purge();
  908. }
  909. bool CBugReporter::PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list )
  910. {
  911. TRK_UINT rc;
  912. rc = TrkInitChoiceList( trkHandle, listname, SCR_TYPE );
  913. if ( TRK_SUCCESS != rc )
  914. {
  915. ReportError( rc, "TrkInitChoiceList", listname );
  916. return false;
  917. }
  918. else
  919. {
  920. char sz[ 256 ];
  921. while ( TrkGetNextChoice( trkHandle, sizeof( sz ), sz ) != TRK_E_END_OF_LIST )
  922. {
  923. CUtlSymbol sym = m_BugStrings.AddString( sz );
  924. list.AddToTail( sym );
  925. }
  926. }
  927. return true;
  928. }
  929. // owner, not required <<Unassigned>>
  930. // area <<None>>
  931. bool CBugReporter::PopulateLists()
  932. {
  933. CUtlSymbol unassigned = m_BugStrings.AddString( "<<Unassigned>>" );
  934. CUtlSymbol none = m_BugStrings.AddString( "<<None>>" );
  935. m_Area.AddToTail( none );
  936. m_MapNumber.AddToTail( none );
  937. m_Names.AddToTail( unassigned );
  938. m_InternalNameMapping.Insert( "<<Unassigned>>", unassigned );
  939. m_SortedDisplayNames.AddToTail( unassigned );
  940. PopulateChoiceList( "Severity", m_Severity );
  941. PopulateChoiceList( "Report Type", m_ReportType );
  942. PopulateChoiceList( "Area", m_Area );
  943. PopulateChoiceList( "Area@Dir%Map", m_AreaMap );
  944. PopulateChoiceList( "Map Number", m_MapNumber );
  945. PopulateChoiceList( "Priority", m_Priority );
  946. // Need to gather names, too
  947. TRK_UINT rc;
  948. rc = TrkInitUserList( trkHandle );
  949. if ( TRK_SUCCESS != rc )
  950. {
  951. ReportError( rc, "TrkInitUserList", "Couldn't get userlist" );
  952. return false;
  953. }
  954. else
  955. {
  956. char sz[ 256 ];
  957. while ( TrkGetNextUser( trkHandle, sizeof( sz ), sz ) != TRK_E_END_OF_LIST )
  958. {
  959. // Now lookup display name for user
  960. char displayname[ 256 ];
  961. rc = TrkGetUserFullName( trkHandle, sz, sizeof( displayname ), displayname );
  962. if ( TRK_SUCCESS == rc )
  963. {
  964. // Fill in lookup table
  965. CUtlSymbol internal_name_sym = m_BugStrings.AddString( sz );
  966. CUtlSymbol display_name_sym = m_BugStrings.AddString( displayname );
  967. m_Names.AddToTail( internal_name_sym );
  968. m_InternalNameMapping.Insert( displayname, internal_name_sym );
  969. m_SortedDisplayNames.AddToTail( display_name_sym );
  970. }
  971. }
  972. // Now sort display names
  973. int c = m_SortedDisplayNames.Count();
  974. for ( int i = 1 ; i < c; i++ )
  975. {
  976. for ( int j = i + 1; j < c; j++ )
  977. {
  978. char const *p1 = m_BugStrings.String( m_SortedDisplayNames[ i ] );
  979. char const *p2 = m_BugStrings.String( m_SortedDisplayNames[ j ] );
  980. int cmp = Q_stricmp( p1, p2 );
  981. if ( cmp > 0 )
  982. {
  983. CUtlSymbol t = m_SortedDisplayNames[ i ];
  984. m_SortedDisplayNames[ i ] = m_SortedDisplayNames[ j ];
  985. m_SortedDisplayNames[ j ] = t;
  986. }
  987. }
  988. }
  989. }
  990. return true;
  991. }
  992. EXPOSE_SINGLE_INTERFACE( CBugReporter, IBugReporter, INTERFACEVERSION_BUGREPORTER );