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.

922 lines
23 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 "winlite.h"
  10. #include <time.h>
  11. #ifdef WIN32
  12. #include <io.h>
  13. #include <direct.h>
  14. #else
  15. #include <sys/stat.h>
  16. #define _stat stat
  17. #endif
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include "basetypes.h"
  22. #include "utlvector.h"
  23. #include "utlsymbol.h"
  24. #include "utldict.h"
  25. #include "utlbuffer.h"
  26. #include "utlmap.h"
  27. #include "bugreporter/bugreporter.h"
  28. #include "filesystem_tools.h"
  29. #include "KeyValues.h"
  30. #include "vstdlib/random.h"
  31. #ifdef WIN32
  32. #define BUGSUB_CONFIG "\\\\bugbait\\bugsub\\config.txt"
  33. #else
  34. #ifdef OSX
  35. #define BUGSUB_CONFIG "/Volumes/bugsub/config.txt"
  36. #define BUGSUB_MOUNT "/Volumes/bugsub"
  37. #define BUGSUB_MOUNT_COMMAND "mount_smbfs //guest:@bugbait.valvesoftware.com/bugsub " BUGSUB_MOUNT
  38. #else
  39. // We can't do sudo here, so we rely on /etc/fstab being setup for '/mnt/bugsub'. See comment in CBugReporter::Init().
  40. #define BUGSUB_CONFIG "/mnt/bugsub/config.txt"
  41. #define BUGSUB_MOUNT "/mnt/bugsub"
  42. #define BUGSUB_MOUNT_COMMAND "mount /mnt/bugsub"
  43. #endif
  44. #define BUGSUB_UNMOUNT_COMMAND "umount " BUGSUB_MOUNT
  45. #endif
  46. class CBugReporter *g_bugreporter = NULL;
  47. class CBug
  48. {
  49. public:
  50. CBug()
  51. {
  52. Clear();
  53. }
  54. void Clear()
  55. {
  56. Q_memset( title, 0, sizeof( title ) );
  57. Q_memset( desc, 0, sizeof( desc ) );
  58. Q_memset( submitter, 0, sizeof( submitter ) );
  59. Q_memset( owner, 0, sizeof( owner ) );
  60. Q_memset( severity, 0, sizeof( severity ) );
  61. Q_memset( priority, 0, sizeof( priority ) );
  62. Q_memset( area, 0, sizeof( area ) );
  63. Q_memset( mapnumber, 0, sizeof( mapnumber) );
  64. Q_memset( reporttype, 0, sizeof( reporttype ) );
  65. Q_memset( level, 0, sizeof( level ) );
  66. Q_memset( build, 0, sizeof( build ) );
  67. Q_memset( position, 0, sizeof( position ) );
  68. Q_memset( orientation, 0, sizeof( orientation ) );
  69. Q_memset( screenshot_unc, 0, sizeof( screenshot_unc ) );
  70. Q_memset( savegame_unc, 0, sizeof( savegame_unc ) );
  71. Q_memset( bsp_unc, 0, sizeof( bsp_unc ) );
  72. Q_memset( vmf_unc, 0, sizeof( vmf_unc ) );
  73. Q_memset( driverinfo, 0, sizeof( driverinfo ) );
  74. Q_memset( misc, 0, sizeof( misc ) );
  75. includedfiles.Purge();
  76. }
  77. char title[ 256 ];
  78. char desc[ 8192 ];
  79. char owner[ 256 ];
  80. char submitter[ 256 ];
  81. char severity[ 256 ];
  82. char priority[ 256 ];
  83. char area[ 256 ];
  84. char mapnumber[ 256 ];
  85. char reporttype[ 256 ];
  86. char level[ 256 ];
  87. char build[ 256 ];
  88. char position[ 256 ];
  89. char orientation[ 256 ];
  90. char screenshot_unc[ 256 ];
  91. char savegame_unc[ 256 ];
  92. char bsp_unc[ 256 ];
  93. char vmf_unc[ 256 ];
  94. char driverinfo[ 2048 ];
  95. char misc[ 1024 ];
  96. struct incfile
  97. {
  98. char name[ 256 ];
  99. };
  100. CUtlVector< incfile > includedfiles;
  101. };
  102. class CBugReporter : public IBugReporter
  103. {
  104. public:
  105. CBugReporter();
  106. virtual ~CBugReporter();
  107. // Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  108. virtual bool Init( CreateInterfaceFn engineFactory );
  109. virtual void Shutdown();
  110. virtual bool IsPublicUI() { return false; }
  111. virtual char const *GetUserName();
  112. virtual char const *GetUserName_Display();
  113. virtual int GetNameCount();
  114. virtual char const *GetName( int index );
  115. virtual int GetDisplayNameCount();
  116. virtual char const *GetDisplayName( int index );
  117. virtual char const *GetUserNameForIndex( int index );
  118. virtual char const *GetDisplayNameForUserName( char const *username );
  119. virtual char const *GetUserNameForDisplayName( char const *display );
  120. virtual char const *GetAreaMapForArea( char const * area);
  121. virtual int GetSeverityCount();
  122. virtual char const *GetSeverity( int index );
  123. virtual int GetPriorityCount();
  124. virtual char const *GetPriority( int index );
  125. virtual int GetAreaCount();
  126. virtual char const *GetArea( int index );
  127. virtual int GetAreaMapCount();
  128. virtual char const *GetAreaMap( int index );
  129. virtual int GetMapNumberCount();
  130. virtual char const *GetMapNumber( int index );
  131. virtual int GetReportTypeCount();
  132. virtual char const *GetReportType( int index );
  133. virtual char const *GetRepositoryURL( void );
  134. virtual char const *GetSubmissionURL( void );
  135. virtual int GetLevelCount(int area);
  136. virtual char const *GetLevel(int area, int index );
  137. // Submission API
  138. virtual void StartNewBugReport();
  139. virtual void CancelNewBugReport();
  140. virtual bool CommitBugReport( int& bugSubmissionId );
  141. virtual void SetTitle( char const *title );
  142. virtual void SetDescription( char const *description );
  143. // NULL for current user
  144. virtual void SetSubmitter( char const *username = 0 );
  145. virtual void SetOwner( char const *username );
  146. virtual void SetSeverity( char const *severity );
  147. virtual void SetPriority( char const *priority );
  148. virtual void SetArea( char const *area );
  149. virtual void SetMapNumber ( char const *mapnumber );
  150. virtual void SetReportType( char const *reporttype );
  151. virtual void SetLevel( char const *levelnamne );
  152. virtual void SetPosition( char const *position );
  153. virtual void SetOrientation( char const *pitch_yaw_roll );
  154. virtual void SetBuildNumber( char const *build_num );
  155. virtual void SetScreenShot( char const *screenshot_unc_address );
  156. virtual void SetSaveGame( char const *savegame_unc_address );
  157. virtual void SetBSPName( char const *bsp_unc_address );
  158. virtual void SetVMFName( char const *vmf_unc_address );
  159. virtual void AddIncludedFile( char const *filename );
  160. virtual void ResetIncludedFiles();
  161. virtual void SetZipAttachmentName( char const *zipfilename ) {} // only used by public bug reporter
  162. virtual void SetDriverInfo( char const *info );
  163. virtual void SetMiscInfo( char const *info );
  164. // These are stubbed here, but are used by the public version...
  165. virtual void SetCSERAddress( const struct netadr_s& adr ) {}
  166. virtual void SetExeName( char const *exename ) {}
  167. virtual void SetGameDirectory( char const *pchGamedir ) {}
  168. virtual void SetRAM( int ram ) {}
  169. virtual void SetCPU( int cpu ) {}
  170. virtual void SetProcessor( char const *processor ) {}
  171. virtual void SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device ) {}
  172. virtual void SetOSVersion( char const *osversion ) {}
  173. virtual void SetSteamUserID( void *steamid, int idsize ) {};
  174. bool SymbolLessThan(const CUtlSymbol &sym1, const CUtlSymbol &sym2);
  175. private:
  176. bool PopulateLists();
  177. bool PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list );
  178. CUtlSymbolTable m_BugStrings;
  179. CUtlVector< CUtlSymbol > m_Severity;
  180. CUtlVector< CUtlSymbol > m_SortedDisplayNames;
  181. CUtlVector< CUtlSymbol > m_SortedUserNames;
  182. CUtlVector< CUtlSymbol > m_Priority;
  183. CUtlVector< CUtlSymbol > m_Area;
  184. CUtlVector< CUtlSymbol > m_AreaMap;
  185. CUtlVector< CUtlSymbol > m_MapNumber;
  186. CUtlVector< CUtlSymbol > m_ReportType;
  187. CUtlMap<CUtlSymbol, CUtlVector< CUtlSymbol > *> m_LevelMap;
  188. CUtlSymbol m_UserName;
  189. CBug *m_pBug;
  190. char m_BugRootDirectory[512];
  191. KeyValues *m_OptionsFile;
  192. int m_CurrentBugID;
  193. char m_CurrentBugDirectory[512];
  194. bool m_bMountedBugSub;
  195. };
  196. bool CUtlSymbol_LessThan(const CUtlSymbol &sym1, const CUtlSymbol &sym2)
  197. {
  198. return g_bugreporter->SymbolLessThan(sym1, sym2);
  199. }
  200. CBugReporter::CBugReporter()
  201. {
  202. m_pBug = NULL;
  203. m_CurrentBugID = 0;
  204. m_bMountedBugSub = false;
  205. m_LevelMap.SetLessFunc(&CUtlSymbol_LessThan);
  206. g_bugreporter = this;
  207. }
  208. CBugReporter::~CBugReporter()
  209. {
  210. m_BugStrings.RemoveAll();
  211. m_Severity.Purge();
  212. m_SortedDisplayNames.Purge();
  213. m_Priority.Purge();
  214. m_Area.Purge();
  215. m_MapNumber.Purge();
  216. m_ReportType.Purge();
  217. m_LevelMap.RemoveAll();
  218. delete m_pBug;
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  222. // Output : Returns true on success, false on failure.
  223. //-----------------------------------------------------------------------------
  224. bool CBugReporter::Init( CreateInterfaceFn engineFactory )
  225. {
  226. // Load our bugreporter_text options file
  227. m_OptionsFile = new KeyValues( "OptionsFile" );
  228. #ifdef POSIX
  229. // check if we can see the config file
  230. struct _stat mount_info;
  231. if (_stat(BUGSUB_CONFIG, &mount_info))
  232. {
  233. // if not we may need to mount bugbait
  234. if ( _stat(BUGSUB_MOUNT, &mount_info ) )
  235. {
  236. // make the mount dir if needed
  237. mkdir( BUGSUB_MOUNT, S_IRWXU | S_IRWXG | S_IRWXO );
  238. }
  239. // now run the smbmount on it
  240. system( BUGSUB_MOUNT_COMMAND );
  241. #ifdef LINUX
  242. if( _stat( BUGSUB_CONFIG, &mount_info ) )
  243. {
  244. Color clr( 255, 100, 50, 255 );
  245. // The mount failed - probably because the /etc/fstab entry is missing?
  246. ConColorMsg( clr, "ERROR: failed to mount '" BUGSUB_MOUNT "' with '" BUGSUB_MOUNT_COMMAND "'.\n" );
  247. ConColorMsg( clr, "Bugsub not set up yet? Do 'sudo apt-get install smbfs', 'sudo mkdir /mnt/bugsub', and add this /etc/fstab:\n" );
  248. ConColorMsg( clr, " bugbait.valvesoftware.com/bugsub /mnt/bugsub smbfs rw,user,username=guest,password=,noauto 0 0\n" );
  249. return false;
  250. }
  251. #endif
  252. m_bMountedBugSub = true;
  253. }
  254. #elif defined(WIN32)
  255. #else
  256. #error "need to get to \\bugbait somehow"
  257. #endif
  258. // open file old skool way to avoid steam filesystem restrictions
  259. struct _stat cfg_info;
  260. if (_stat(BUGSUB_CONFIG, &cfg_info)) {
  261. AssertMsg( 0, "Failed to find bugreporter options file." );
  262. return false;
  263. }
  264. int buf_size = (cfg_info.st_size + 1);
  265. char *buf = new char[buf_size];
  266. FILE *fp = fopen(BUGSUB_CONFIG, "rb");
  267. if (!fp) {
  268. AssertMsg(0, "failed to open bugreporter options file" );
  269. delete [] buf;
  270. return false;
  271. }
  272. fread(buf, cfg_info.st_size, 1, fp);
  273. fclose(fp);
  274. buf[cfg_info.st_size] = 0;
  275. if ( !m_OptionsFile->LoadFromBuffer(BUGSUB_CONFIG, buf) )
  276. {
  277. AssertMsg( 0, "Failed to load bugreporter_text options file." );
  278. delete [] buf;
  279. return false;
  280. }
  281. #ifdef WIN32
  282. V_strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory", "." ), sizeof(m_BugRootDirectory) );
  283. #elif defined(OSX)
  284. V_strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory_osx", BUGSUB_MOUNT ), sizeof(m_BugRootDirectory) );
  285. #elif defined(LINUX)
  286. V_strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory_linux", BUGSUB_MOUNT ), sizeof(m_BugRootDirectory) );
  287. #else
  288. #error
  289. #endif
  290. PopulateLists();
  291. #ifdef WIN32
  292. m_UserName = m_BugStrings.AddString(getenv( "username" ));
  293. #elif POSIX
  294. m_UserName = m_BugStrings.AddString(getenv( "USER" ));
  295. #else
  296. #error
  297. #endif
  298. delete [] buf;
  299. return true;
  300. }
  301. void CBugReporter::Shutdown()
  302. {
  303. #ifdef POSIX
  304. if ( m_bMountedBugSub )
  305. {
  306. system( BUGSUB_UNMOUNT_COMMAND );
  307. }
  308. #endif
  309. }
  310. char const *CBugReporter::GetUserName()
  311. {
  312. return m_BugStrings.String( m_UserName );
  313. }
  314. char const *CBugReporter::GetUserName_Display()
  315. {
  316. return GetDisplayNameForUserName( GetUserName() );
  317. }
  318. int CBugReporter::GetNameCount()
  319. {
  320. return GetDisplayNameCount();
  321. }
  322. char const *CBugReporter::GetName( int index )
  323. {
  324. return GetDisplayName(index);
  325. }
  326. int CBugReporter::GetDisplayNameCount()
  327. {
  328. return m_SortedDisplayNames.Count();
  329. }
  330. char const *CBugReporter::GetDisplayName( int index )
  331. {
  332. if ( index < 0 || index >= (int)m_SortedDisplayNames.Count() )
  333. return "<<Invalid>>";
  334. return m_BugStrings.String( m_SortedDisplayNames[ index ] );
  335. }
  336. char const *CBugReporter::GetUserNameForIndex( int index )
  337. {
  338. if ( index < 0 || index >= (int)m_SortedUserNames.Count() )
  339. return "<<Invalid>>";
  340. return m_BugStrings.String( m_SortedUserNames[ index ] );
  341. }
  342. char const *CBugReporter::GetDisplayNameForUserName( char const *username )
  343. {
  344. CUtlSymbol username_sym = m_BugStrings.Find(username);
  345. FOR_EACH_VEC(m_SortedUserNames, index) {
  346. if (m_SortedUserNames[index] == username_sym) {
  347. return GetDisplayName(index);
  348. }
  349. }
  350. return username;
  351. }
  352. char const *CBugReporter::GetUserNameForDisplayName( char const *display )
  353. {
  354. CUtlSymbol display_sym = m_BugStrings.Find(display);
  355. FOR_EACH_VEC(m_SortedDisplayNames, index) {
  356. if (m_SortedDisplayNames[index] == display_sym) {
  357. return GetUserNameForIndex(index);
  358. }
  359. }
  360. return display;
  361. }
  362. char const *CBugReporter::GetAreaMapForArea( char const *area)
  363. {
  364. CUtlSymbol area_sym = m_BugStrings.Find(area);
  365. FOR_EACH_VEC(m_Area, index) {
  366. if (m_Area[index] == area_sym && index > 0) {
  367. char const *areamap = m_BugStrings.String(m_AreaMap[index-1]);
  368. return areamap+1;
  369. }
  370. }
  371. return "<<Invalid>>";
  372. }
  373. int CBugReporter::GetSeverityCount()
  374. {
  375. return m_Severity.Count() ;
  376. }
  377. char const *CBugReporter::GetSeverity( int index )
  378. {
  379. if ( index < 0 || index >= m_Severity.Count() )
  380. return "<<Invalid>>";
  381. return m_BugStrings.String( m_Severity[ index ] );
  382. }
  383. int CBugReporter::GetPriorityCount()
  384. {
  385. return m_Priority.Count();
  386. }
  387. char const *CBugReporter::GetPriority( int index )
  388. {
  389. if ( index < 0 || index >= m_Priority.Count() )
  390. return "<<Invalid>>";
  391. return m_BugStrings.String( m_Priority[ index ] );
  392. }
  393. int CBugReporter::GetAreaCount()
  394. {
  395. return m_Area.Count();
  396. }
  397. char const *CBugReporter::GetArea( int index )
  398. {
  399. if ( index < 0 || index >= m_Area.Count() )
  400. return "<<Invalid>>";
  401. return m_BugStrings.String( m_Area[ index ] );
  402. }
  403. int CBugReporter::GetAreaMapCount()
  404. {
  405. return m_AreaMap.Count();
  406. }
  407. char const *CBugReporter::GetAreaMap( int index )
  408. {
  409. if ( index < 0 || index >= m_AreaMap.Count() )
  410. return "<<Invalid>>";
  411. return m_BugStrings.String( m_AreaMap[ index ] );
  412. }
  413. int CBugReporter::GetMapNumberCount()
  414. {
  415. return m_MapNumber.Count();
  416. }
  417. char const *CBugReporter::GetMapNumber( int index )
  418. {
  419. if ( index < 0 || index >= m_MapNumber.Count() )
  420. return "<<Invalid>>";
  421. return m_BugStrings.String( m_MapNumber[ index ] );
  422. }
  423. int CBugReporter::GetReportTypeCount()
  424. {
  425. return m_ReportType.Count();
  426. }
  427. char const *CBugReporter::GetReportType( int index )
  428. {
  429. if ( index < 0 || index >= m_ReportType.Count() )
  430. return "<<Invalid>>";
  431. return m_BugStrings.String( m_ReportType[ index ] );
  432. }
  433. char const *CBugReporter::GetRepositoryURL( void )
  434. {
  435. return m_BugRootDirectory;
  436. }
  437. // only valid after calling CBugReporter::StartNewBugReport()
  438. char const *CBugReporter::GetSubmissionURL( void )
  439. {
  440. return m_CurrentBugDirectory;
  441. }
  442. int CBugReporter::GetLevelCount(int area)
  443. {
  444. CUtlSymbol area_sym = m_AreaMap[area-1];
  445. int area_index = m_LevelMap.Find(area_sym);
  446. if (m_LevelMap.IsValidIndex(area_index))
  447. {
  448. CUtlVector<CUtlSymbol> *levels = m_LevelMap[area_index];
  449. return levels->Count();
  450. }
  451. return 0;
  452. }
  453. char const *CBugReporter::GetLevel(int area, int index )
  454. {
  455. CUtlSymbol area_sym = m_AreaMap[area-1];
  456. int area_index = m_LevelMap.Find(area_sym);
  457. if (m_LevelMap.IsValidIndex(area_index))
  458. {
  459. CUtlVector<CUtlSymbol> *levels = m_LevelMap[area_index];
  460. if (index >= 0 && index < levels->Count())
  461. {
  462. return m_BugStrings.String((*levels)[index]);
  463. }
  464. }
  465. return "";
  466. }
  467. void CBugReporter::StartNewBugReport()
  468. {
  469. if ( !m_pBug )
  470. {
  471. m_pBug = new CBug();
  472. }
  473. else
  474. {
  475. m_pBug->Clear();
  476. }
  477. // Find the first available bug number by looking
  478. // for the next directory that doesn't exist.
  479. m_CurrentBugID = 0;
  480. struct tm t;
  481. do
  482. {
  483. VCRHook_LocalTime( &t );
  484. Q_snprintf(m_CurrentBugDirectory, sizeof(m_CurrentBugDirectory), "%s%c%04i%02i%02i-%02i%02i%02i-%s",
  485. m_BugRootDirectory,
  486. CORRECT_PATH_SEPARATOR,
  487. t.tm_year + 1900, t.tm_mon+1, t.tm_mday,
  488. t.tm_hour, t.tm_min, t.tm_sec,
  489. m_BugStrings.String(m_UserName));
  490. if (_access(m_CurrentBugDirectory, 0) != 0)
  491. break;
  492. // sleep for a second or two then try again
  493. ThreadSleep(RandomInt(1000,2000));
  494. } while ( 1 );
  495. _mkdir(m_CurrentBugDirectory);
  496. }
  497. void CBugReporter::CancelNewBugReport()
  498. {
  499. if ( !m_pBug )
  500. return;
  501. m_pBug->Clear();
  502. m_CurrentBugID = 0;
  503. }
  504. static void OutputField( CUtlBuffer &outbuf, char const *pFieldName, char const *pFieldValue )
  505. {
  506. if ( pFieldValue && pFieldValue[0] )
  507. {
  508. char const *pTmpString = V_AddBackSlashesToSpecialChars( pFieldValue );
  509. outbuf.Printf( "%s=\"%s\"\n", pFieldName, pTmpString );
  510. delete[] pTmpString;
  511. }
  512. }
  513. bool CBugReporter::CommitBugReport( int& bugSubmissionId )
  514. {
  515. bugSubmissionId = m_CurrentBugID;
  516. if ( !m_pBug )
  517. return false;
  518. // Now create the bug descriptor file, and dump all the text keys in it
  519. CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER);
  520. OutputField( buf, "Title", m_pBug->title );
  521. OutputField( buf, "Owner", m_pBug->owner );
  522. OutputField( buf, "Submitter", m_pBug->submitter );
  523. OutputField( buf, "Severity", m_pBug->severity );
  524. // OutputField( buf, "Type", m_pBug->reporttype );
  525. // OutputField( buf, "Priority", m_pBug->priority );
  526. OutputField( buf, "Area", m_pBug->area );
  527. OutputField( buf, "Level", m_pBug->mapnumber );
  528. OutputField( buf, "Description", m_pBug->desc );
  529. //OutputField( buf, "Level", m_pBug->level );
  530. OutputField( buf, "Build", m_pBug->build );
  531. OutputField( buf, "Position", m_pBug->position );
  532. OutputField( buf, "Orientation", m_pBug->orientation );
  533. OutputField( buf, "Screenshot", m_pBug->screenshot_unc );
  534. OutputField( buf, "Savegame", m_pBug->savegame_unc );
  535. OutputField( buf, "Bsp", m_pBug->bsp_unc );
  536. OutputField( buf, "vmf", m_pBug->vmf_unc );
  537. // if ( m_pBug->includedfiles.Count() > 0 )
  538. // {
  539. // int c = m_pBug->includedfiles.Count();
  540. // for ( int i = 0 ; i < c; ++i )
  541. // {
  542. // buf.Printf( "include: %s\n", m_pBug->includedfiles[ i ].name );
  543. // }
  544. // }
  545. OutputField( buf, "DriverInfo", m_pBug->driverinfo );
  546. OutputField( buf, "Misc", m_pBug->misc );
  547. // Write it out to the file
  548. // Need to use native calls to bypass steam filesystem
  549. char szBugFileName[1024];
  550. Q_snprintf(szBugFileName, sizeof(szBugFileName), "%s%cbug.txt", m_CurrentBugDirectory, CORRECT_PATH_SEPARATOR );
  551. FILE *fp = fopen(szBugFileName, "wb");
  552. if (!fp)
  553. return false;
  554. fprintf(fp, "%s", (char *)buf.Base());
  555. fclose(fp);
  556. // Clear the bug
  557. m_pBug->Clear();
  558. return true;
  559. }
  560. void CBugReporter::SetTitle( char const *title )
  561. {
  562. Assert( m_pBug );
  563. Q_strncpy( m_pBug->title, title, sizeof( m_pBug->title ) );
  564. }
  565. void CBugReporter::SetDescription( char const *description )
  566. {
  567. Assert( m_pBug );
  568. Q_strncpy( m_pBug->desc, description, sizeof( m_pBug->desc ) );
  569. }
  570. void CBugReporter::SetSubmitter( char const *username /* = 0 */)
  571. {
  572. if ( !username )
  573. {
  574. username = GetUserName();
  575. }
  576. Assert( m_pBug );
  577. Q_strncpy( m_pBug->submitter, username, sizeof( m_pBug->submitter ) );
  578. }
  579. void CBugReporter::SetOwner( char const *username )
  580. {
  581. Assert( m_pBug );
  582. Q_strncpy( m_pBug->owner, username, sizeof( m_pBug->owner ) );
  583. }
  584. void CBugReporter::SetSeverity( char const *severity )
  585. {
  586. Assert( m_pBug );
  587. Q_strncpy( m_pBug->severity, severity, sizeof( m_pBug->severity ) );
  588. }
  589. void CBugReporter::SetPriority( char const *priority )
  590. {
  591. Assert( m_pBug );
  592. Q_strncpy( m_pBug->priority, priority, sizeof( m_pBug->priority ) );
  593. }
  594. void CBugReporter::SetArea( char const *area )
  595. {
  596. Assert( m_pBug );
  597. char const *game = GetAreaMapForArea(area);
  598. Q_strncpy( m_pBug->area, game, sizeof( m_pBug->area ) );
  599. }
  600. void CBugReporter::SetMapNumber( char const *mapnumber )
  601. {
  602. Assert( m_pBug);
  603. Q_strncpy( m_pBug->mapnumber, mapnumber, sizeof( m_pBug->mapnumber ) );
  604. }
  605. void CBugReporter::SetReportType( char const *reporttype )
  606. {
  607. Assert( m_pBug );
  608. Q_strncpy( m_pBug->reporttype, reporttype, sizeof( m_pBug->reporttype ) );
  609. }
  610. void CBugReporter::SetLevel( char const *levelnamne )
  611. {
  612. Assert( m_pBug );
  613. Q_strncpy( m_pBug->level, levelnamne, sizeof( m_pBug->level ) );
  614. }
  615. void CBugReporter::SetDriverInfo( char const *info )
  616. {
  617. Assert( m_pBug );
  618. Q_strncpy( m_pBug->driverinfo, info, sizeof( m_pBug->driverinfo ) );
  619. }
  620. void CBugReporter::SetMiscInfo( char const *info )
  621. {
  622. Assert( m_pBug );
  623. Q_strncpy( m_pBug->misc, info, sizeof( m_pBug->misc ) );
  624. }
  625. void CBugReporter::SetPosition( char const *position )
  626. {
  627. Assert( m_pBug );
  628. Q_strncpy( m_pBug->position, position, sizeof( m_pBug->position ) );
  629. }
  630. void CBugReporter::SetOrientation( char const *pitch_yaw_roll )
  631. {
  632. Assert( m_pBug );
  633. Q_strncpy( m_pBug->orientation, pitch_yaw_roll, sizeof( m_pBug->orientation ) );
  634. }
  635. void CBugReporter::SetBuildNumber( char const *build_num )
  636. {
  637. Assert( m_pBug );
  638. Q_strncpy( m_pBug->build, build_num, sizeof( m_pBug->build ) );
  639. }
  640. void CBugReporter::SetScreenShot( char const *screenshot_unc_address )
  641. {
  642. Assert( m_pBug );
  643. Q_strncpy( m_pBug->screenshot_unc, screenshot_unc_address, sizeof( m_pBug->screenshot_unc ) );
  644. }
  645. void CBugReporter::SetSaveGame( char const *savegame_unc_address )
  646. {
  647. Assert( m_pBug );
  648. Q_strncpy( m_pBug->savegame_unc, savegame_unc_address, sizeof( m_pBug->savegame_unc ) );
  649. }
  650. void CBugReporter::SetBSPName( char const *bsp_unc_address )
  651. {
  652. Assert( m_pBug );
  653. Q_strncpy( m_pBug->bsp_unc, bsp_unc_address, sizeof( m_pBug->bsp_unc ) );
  654. }
  655. void CBugReporter::SetVMFName( char const *vmf_unc_address )
  656. {
  657. Assert( m_pBug );
  658. Q_strncpy( m_pBug->vmf_unc, vmf_unc_address, sizeof( m_pBug->vmf_unc ) );
  659. }
  660. void CBugReporter::AddIncludedFile( char const *filename )
  661. {
  662. CBug::incfile includedfile;
  663. Q_strncpy( includedfile.name, filename, sizeof( includedfile.name ) );
  664. m_pBug->includedfiles.AddToTail( includedfile );
  665. }
  666. void CBugReporter::ResetIncludedFiles()
  667. {
  668. m_pBug->includedfiles.Purge();
  669. }
  670. bool CBugReporter::PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list )
  671. {
  672. // Read choice lists from text file
  673. KeyValues *pKV = m_OptionsFile->FindKey( listname );
  674. pKV = pKV->GetFirstSubKey();
  675. while ( pKV )
  676. {
  677. CUtlSymbol sym = m_BugStrings.AddString( pKV->GetName() );
  678. list.AddToTail( sym );
  679. pKV = pKV->GetNextKey();
  680. }
  681. return true;
  682. }
  683. bool CBugReporter::SymbolLessThan(const CUtlSymbol &sym1, const CUtlSymbol &sym2)
  684. {
  685. const char *string1 = m_BugStrings.String(sym1);
  686. const char *string2 = m_BugStrings.String(sym2);
  687. return Q_stricmp(string1, string2) < 0;
  688. }
  689. // owner, not required <<Unassigned>>
  690. // area <<None>>
  691. bool CBugReporter::PopulateLists()
  692. {
  693. CUtlSymbol none = m_BugStrings.AddString( "<<None>>" );
  694. m_Area.AddToTail( none );
  695. PopulateChoiceList( "Severity", m_Severity );
  696. // Get developer names from text file
  697. KeyValues *pKV = m_OptionsFile->FindKey( "Names" );
  698. pKV = pKV->GetFirstSubKey();
  699. while ( pKV )
  700. {
  701. // Fill in lookup table
  702. CUtlSymbol display_name_sym = m_BugStrings.AddString( pKV->GetName() );
  703. CUtlSymbol user_name_sym = m_BugStrings.AddString( pKV->GetString() );
  704. m_SortedDisplayNames.AddToTail( display_name_sym );
  705. m_SortedUserNames.AddToTail( user_name_sym );
  706. pKV = pKV->GetNextKey();
  707. }
  708. pKV = m_OptionsFile->FindKey( "Area" );
  709. pKV = pKV->GetFirstSubKey();
  710. while(pKV)
  711. {
  712. char const *area = pKV->GetName();
  713. char const *game = pKV->GetString();
  714. char areamap[256];
  715. Q_snprintf(areamap, sizeof(areamap), "@%s", game);
  716. CUtlSymbol area_sym = m_BugStrings.AddString(area);
  717. CUtlSymbol area_map_sym = m_BugStrings.AddString(areamap);
  718. m_Area.AddToTail( area_sym );
  719. m_AreaMap.AddToTail( area_map_sym );
  720. pKV = pKV->GetNextKey();
  721. }
  722. pKV = m_OptionsFile->FindKey( "Level" );
  723. pKV = pKV->GetFirstSubKey();
  724. while(pKV)
  725. {
  726. char const *level = pKV->GetName();
  727. char const *area = pKV->GetString();
  728. char areamap[256];
  729. Q_snprintf(areamap, sizeof(areamap), "@%s", area);
  730. CUtlSymbol level_sym = m_BugStrings.AddString(level);
  731. CUtlSymbol area_sym = m_BugStrings.Find(areamap);
  732. if (!area_sym.IsValid())
  733. {
  734. area_sym = m_BugStrings.AddString(areamap);
  735. }
  736. unsigned index = m_LevelMap.Find(area_sym);
  737. CUtlVector<CUtlSymbol> *levels = 0;
  738. if (m_LevelMap.IsValidIndex(index))
  739. {
  740. levels = m_LevelMap[index];
  741. }
  742. else
  743. {
  744. levels = new CUtlVector<CUtlSymbol>;
  745. Assert(levels);
  746. m_LevelMap.Insert(area_sym, levels);
  747. }
  748. if (level)
  749. {
  750. levels->AddToTail(level_sym);
  751. }
  752. pKV = pKV->GetNextKey();
  753. }
  754. return true;
  755. }
  756. EXPOSE_SINGLE_INTERFACE( CBugReporter, IBugReporter, INTERFACEVERSION_BUGREPORTER );