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.

1005 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include <windows.h>
  9. #include "tier0/dbg.h"
  10. #include "utldict.h"
  11. #include "filesystem.h"
  12. #include "KeyValues.h"
  13. #include "cmdlib.h"
  14. #include "interface.h"
  15. #include "imysqlwrapper.h"
  16. #include "../bugreporter/trktool.h"
  17. #include "utlbuffer.h"
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <direct.h>
  21. bool uselogfile = false;
  22. static bool spewed = false;
  23. static char workingdir[ 256 ];
  24. #define SCR_TYPE 1
  25. #define DEFAULT_DBMS "tracker"
  26. #define DEFAULT_USERNAME "PublicUser"
  27. #define DEFAULT_PASSWORD DEFAULT_USERNAME
  28. #define BUG_REPOSITORY_FMT "\\\\fileserver\\bugs\\public\\%s\\%s\\%s.zip"
  29. struct BugField_t
  30. {
  31. BugField_t()
  32. {
  33. value[ 0 ] = 0;
  34. numvalue = 0;
  35. trkfield[ 0 ] = 0;
  36. isdesc = false;
  37. isnumeric = false;
  38. }
  39. char value[ 8192 ];
  40. int numvalue;
  41. char trkfield[ 256 ];
  42. bool isdesc;
  43. bool isnumeric;
  44. };
  45. #define SQL_SETVALUE( fieldname, sqlcolumn ) Q_strncpy( bug.m_pBug->fieldname, sqlcolumn.String(), sizeof( bug.m_pBug->fieldname ) );
  46. #define SQL_SETVALUESTRING( fieldname, str ) Q_strncpy( bug.m_pBug->fieldname, str, sizeof( bug.m_pBug->fieldname ) );
  47. class CBugReporter
  48. {
  49. public:
  50. CBugReporter();
  51. virtual ~CBugReporter();
  52. // Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  53. virtual bool Init( char const *projectname );
  54. virtual void Shutdown();
  55. virtual bool IsPublicUI() { return false; }
  56. // Submission API
  57. virtual void StartNewBugReport();
  58. virtual void CancelNewBugReport();
  59. virtual bool CommitBugReport( int& bugSubmissionId );
  60. virtual void AddField( char const *fieldname, char const *value, bool isdesc = false );
  61. virtual void AddNumericField( char const *fieldname, int value );
  62. private:
  63. void ReportError(TRK_UINT rc, char const *func, char const *msg );
  64. TRK_UINT Login(TRK_HANDLE* pTrkHandle, char const *projectname );
  65. void SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src );
  66. TRK_HANDLE trkHandle;
  67. TRK_RECORD_HANDLE trkRecHandle;
  68. public:
  69. CUtlVector< BugField_t > m_Fields;
  70. };
  71. void CBugReporter::AddField( char const *fieldname, char const *value, bool isdesc /*=false*/ )
  72. {
  73. BugField_t fld;
  74. Q_strncpy( fld.value, value, sizeof( fld.value ) );
  75. fld.isnumeric = false;
  76. Q_strncpy( fld.trkfield, fieldname, sizeof( fld.trkfield ) );
  77. fld.isdesc = isdesc;
  78. m_Fields.AddToTail( fld );
  79. }
  80. void CBugReporter::AddNumericField( char const *fieldname, int value )
  81. {
  82. BugField_t fld;
  83. fld.numvalue = value;
  84. fld.isnumeric = true;
  85. Q_strncpy( fld.trkfield, fieldname, sizeof( fld.trkfield ) );
  86. fld.isdesc = false;
  87. m_Fields.AddToTail( fld );
  88. }
  89. CBugReporter::CBugReporter()
  90. {
  91. trkHandle = (TRK_HANDLE)0;
  92. trkRecHandle = (TRK_RECORD_HANDLE)0;
  93. }
  94. CBugReporter::~CBugReporter()
  95. {
  96. m_Fields.RemoveAll();
  97. }
  98. struct TRKELookup
  99. {
  100. unsigned int id;
  101. char const *str;
  102. };
  103. #define TRKERROR( id ) { id, #id }
  104. static TRKELookup g_Lookup[] =
  105. {
  106. TRKERROR( TRK_SUCCESS ),
  107. TRKERROR( TRK_E_VERSION_MISMATCH ),
  108. TRKERROR( TRK_E_OUT_OF_MEMORY ),
  109. TRKERROR( TRK_E_BAD_HANDLE ),
  110. TRKERROR( TRK_E_BAD_INPUT_POINTER ),
  111. TRKERROR( TRK_E_BAD_INPUT_VALUE ),
  112. TRKERROR( TRK_E_DATA_TRUNCATED ),
  113. TRKERROR( TRK_E_NO_MORE_DATA ),
  114. TRKERROR( TRK_E_LIST_NOT_INITIALIZED ),
  115. TRKERROR( TRK_E_END_OF_LIST ),
  116. TRKERROR( TRK_E_NOT_LOGGED_IN ),
  117. TRKERROR( TRK_E_SERVER_NOT_PREPARED ),
  118. TRKERROR( TRK_E_BAD_DATABASE_VERSION ),
  119. TRKERROR( TRK_E_UNABLE_TO_CONNECT ),
  120. TRKERROR( TRK_E_UNABLE_TO_DISCONNECT ),
  121. TRKERROR( TRK_E_UNABLE_TO_START_TIMER ),
  122. TRKERROR( TRK_E_NO_DATA_SOURCES ),
  123. TRKERROR( TRK_E_NO_PROJECTS ),
  124. TRKERROR( TRK_E_WRITE_FAILED ),
  125. TRKERROR( TRK_E_PERMISSION_DENIED ),
  126. TRKERROR( TRK_E_SET_FIELD_DENIED ),
  127. TRKERROR( TRK_E_ITEM_NOT_FOUND ),
  128. TRKERROR( TRK_E_CANNOT_ACCESS_DATABASE ),
  129. TRKERROR( TRK_E_CANNOT_ACCESS_QUERY ),
  130. TRKERROR( TRK_E_CANNOT_ACCESS_INTRAY ),
  131. TRKERROR( TRK_E_CANNOT_OPEN_FILE ),
  132. TRKERROR( TRK_E_INVALID_DBMS_TYPE ),
  133. TRKERROR( TRK_E_INVALID_RECORD_TYPE ),
  134. TRKERROR( TRK_E_INVALID_FIELD ),
  135. TRKERROR( TRK_E_INVALID_CHOICE ),
  136. TRKERROR( TRK_E_INVALID_USER ),
  137. TRKERROR( TRK_E_INVALID_SUBMITTER ),
  138. TRKERROR( TRK_E_INVALID_OWNER ),
  139. TRKERROR( TRK_E_INVALID_DATE ),
  140. TRKERROR( TRK_E_INVALID_STORED_QUERY ),
  141. TRKERROR( TRK_E_INVALID_MODE ),
  142. TRKERROR( TRK_E_INVALID_MESSAGE ),
  143. TRKERROR( TRK_E_VALUE_OUT_OF_RANGE ),
  144. TRKERROR( TRK_E_WRONG_FIELD_TYPE ),
  145. TRKERROR( TRK_E_NO_CURRENT_RECORD ),
  146. TRKERROR( TRK_E_NO_CURRENT_NOTE ),
  147. TRKERROR( TRK_E_NO_CURRENT_ATTACHED_FILE ),
  148. TRKERROR( TRK_E_NO_CURRENT_ASSOCIATION ),
  149. TRKERROR( TRK_E_NO_RECORD_BEGIN ),
  150. TRKERROR( TRK_E_NO_MODULE ),
  151. TRKERROR( TRK_E_USER_CANCELLED ),
  152. TRKERROR( TRK_E_SEMAPHORE_TIMEOUT ),
  153. TRKERROR( TRK_E_SEMAPHORE_ERROR ),
  154. TRKERROR( TRK_E_INVALID_SERVER_NAME ),
  155. TRKERROR( TRK_E_NOT_LICENSED )
  156. };
  157. void CBugReporter::ReportError(TRK_UINT rc, char const *func, char const *msg )
  158. {
  159. if ( rc != TRK_SUCCESS )
  160. {
  161. switch (rc)
  162. {
  163. case TRK_E_ITEM_NOT_FOUND:
  164. Msg( "%s %s was not found!\n", func, msg );
  165. break;
  166. case TRK_E_INVALID_FIELD:
  167. Msg( "%s %s Invalid field!\n", func, msg );
  168. break;
  169. default:
  170. int i = 0;
  171. for ( i; i < ARRAYSIZE( g_Lookup ) ; ++i )
  172. {
  173. if ( g_Lookup[ i ].id == rc )
  174. {
  175. Msg( "%s returned %i - %s (%s)!\n", func, rc, g_Lookup[ i ].str, msg );
  176. break;
  177. }
  178. }
  179. if ( i >= ARRAYSIZE( g_Lookup ) )
  180. {
  181. Msg( "%s returned %i - %s! (%s)\n", func, rc, "???", msg );
  182. }
  183. break;
  184. }
  185. }
  186. }
  187. TRK_UINT CBugReporter::Login(TRK_HANDLE* pTrkHandle, char const *projectname )
  188. {
  189. char dbms[50] = DEFAULT_DBMS;
  190. char username[ 50 ];
  191. char password[ 50 ];
  192. Q_strncpy( username, DEFAULT_USERNAME, sizeof( username ) );
  193. Q_strncpy( password, DEFAULT_PASSWORD, sizeof( password ) );
  194. TRK_UINT rc = TrkProjectLogin(*pTrkHandle,
  195. username,
  196. password,
  197. projectname,
  198. NULL,
  199. NULL,
  200. NULL,
  201. NULL,
  202. TRK_USE_INI_FILE_DBMS_LOGIN);
  203. if (rc != TRK_SUCCESS)
  204. {
  205. rc = TrkProjectLogin(*pTrkHandle,
  206. username,
  207. "",
  208. projectname,
  209. NULL,
  210. NULL,
  211. NULL,
  212. NULL,
  213. TRK_USE_INI_FILE_DBMS_LOGIN);
  214. if (rc != TRK_SUCCESS)
  215. {
  216. Msg("Bug reporter init failed: Your tracker password must be your user name or blank.\n");
  217. return rc;
  218. }
  219. }
  220. TrkGetLoginDBMSName(*pTrkHandle, sizeof(dbms), dbms );
  221. char projout[ 256 ];
  222. TrkGetLoginProjectName(*pTrkHandle, sizeof( projout ), projout );
  223. Msg( "Project: %s\n", projout );
  224. Msg( "Server: %s\n", dbms );
  225. return rc;
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res)
  229. // Output : Returns true on success, false on failure.
  230. //-----------------------------------------------------------------------------
  231. bool CBugReporter::Init( char const *projectname )
  232. {
  233. TRK_UINT rc;
  234. rc = TrkHandleAlloc( TRK_VERSION_ID, &trkHandle);
  235. if ( rc != TRK_SUCCESS )
  236. {
  237. ReportError(rc, "TrkHandleAlloc", "Failed to Allocate Tracker Handle!");
  238. return false;
  239. }
  240. // Login to default project out of INI file.
  241. rc = Login( &trkHandle, projectname );
  242. if (rc != TRK_SUCCESS)
  243. {
  244. return false;
  245. }
  246. rc = TrkRecordHandleAlloc(trkHandle, &trkRecHandle);
  247. if (rc != TRK_SUCCESS)
  248. {
  249. ReportError(rc, "TrkRecordHandleAlloc",
  250. "Failed to Allocate Tracker Record Handle!");
  251. return false;
  252. }
  253. return true;
  254. }
  255. void CBugReporter::Shutdown()
  256. {
  257. TRK_UINT rc;
  258. if ( trkRecHandle )
  259. {
  260. rc = TrkRecordHandleFree(&trkRecHandle);
  261. if (rc != TRK_SUCCESS)
  262. {
  263. ReportError(rc, "TrkRecordHandleFree", "Failed to Free Tracker Record Handle!");
  264. }
  265. }
  266. if ( trkHandle )
  267. {
  268. rc = TrkProjectLogout(trkHandle);
  269. if (rc != TRK_SUCCESS)
  270. {
  271. ReportError(rc, "TrkProjectLogout", "Failed to Logout of Project!");
  272. }
  273. else
  274. {
  275. rc = TrkHandleFree(&trkHandle);
  276. if (rc != TRK_SUCCESS)
  277. {
  278. ReportError(rc, "TrkHandleFree", "Failed to Free Tracker Handle!");
  279. }
  280. }
  281. }
  282. }
  283. void CBugReporter::StartNewBugReport()
  284. {
  285. m_Fields.RemoveAll();
  286. }
  287. void CBugReporter::CancelNewBugReport()
  288. {
  289. m_Fields.RemoveAll();
  290. }
  291. void CBugReporter::SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src )
  292. {
  293. out[ 0 ] = 0;
  294. char *dest = out;
  295. src.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  296. char const *replace = "\\BugId\\";
  297. int replace_len = Q_strlen( replace );
  298. for ( int pos = 0; pos <= src.TellPut() && ( ( dest - out ) < outlen ); )
  299. {
  300. char const *str = ( char const * )src.PeekGet( pos );
  301. if ( !Q_strnicmp( str, replace, replace_len ) )
  302. {
  303. *dest++ = '\\';
  304. char num[ 32 ];
  305. Q_snprintf( num, sizeof( num ), "%i", bugid );
  306. char *pnum = num;
  307. while ( *pnum )
  308. {
  309. *dest++ = *pnum++;
  310. }
  311. *dest++ = '\\';
  312. pos += replace_len;
  313. continue;
  314. }
  315. *dest++ = *str;
  316. ++pos;
  317. }
  318. *dest = 0;
  319. }
  320. bool CBugReporter::CommitBugReport( int& bugSubmissionId )
  321. {
  322. bugSubmissionId = -1;
  323. int fieldCount = m_Fields.Count();
  324. if ( fieldCount == 0 )
  325. return false;
  326. TRK_UINT rc = 0;
  327. rc = TrkNewRecordBegin( trkRecHandle, SCR_TYPE );
  328. if ( rc != TRK_SUCCESS )
  329. {
  330. ReportError(rc, "TrkNewRecordBegin",
  331. "Failed to TrkNewRecordBegin!");
  332. return false;
  333. }
  334. CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  335. for ( int i = 0; i < fieldCount; ++i )
  336. {
  337. BugField_t& fld = m_Fields[ i ];
  338. if ( !fld.isdesc )
  339. {
  340. // Populate fields
  341. if ( !fld.isnumeric )
  342. {
  343. rc = TrkSetStringFieldValue(
  344. trkRecHandle,
  345. fld.trkfield,
  346. fld.value );
  347. }
  348. else
  349. {
  350. rc = TrkSetNumericFieldValue(
  351. trkRecHandle,
  352. fld.trkfield,
  353. fld.numvalue );
  354. }
  355. if ( rc != TRK_SUCCESS )
  356. {
  357. char es[ 256 ];
  358. Q_snprintf( es, sizeof( es ), "Failed to add '%s'", fld.trkfield );
  359. ReportError( rc, "TrkSetStringFieldValue", es );
  360. return false;
  361. }
  362. }
  363. else
  364. {
  365. buf.Printf( "%s\n", fld.value );
  366. buf.PutChar( 0 );
  367. rc = TrkSetDescriptionData( trkRecHandle,
  368. buf.TellPut(),
  369. (const char * )buf.Base(),
  370. 0 );
  371. if ( rc != TRK_SUCCESS )
  372. {
  373. ReportError(rc, "TrkSetDescriptionData",
  374. "Failed to set description data!");
  375. return false;
  376. }
  377. }
  378. }
  379. TRK_TRANSACTION_ID id;
  380. rc = TrkNewRecordCommit( trkRecHandle, &id );
  381. if ( rc != TRK_SUCCESS )
  382. {
  383. ReportError(rc, "TrkNewRecordCommit",
  384. "Failed to TrkNewRecordCommit!");
  385. return false;
  386. }
  387. TRK_UINT bugId;
  388. rc = TrkGetNumericFieldValue( trkRecHandle, "Id", &bugId );
  389. if ( rc != TRK_SUCCESS )
  390. {
  391. ReportError(rc, "TrkGetNumericFieldValue",
  392. "Failed to TrkGetNumericFieldValue for bug Id #!");
  393. }
  394. else
  395. {
  396. bugSubmissionId = (int)bugId;
  397. }
  398. rc = TrkGetSingleRecord( trkRecHandle, bugId, SCR_TYPE );
  399. if ( rc != TRK_SUCCESS )
  400. {
  401. ReportError( rc, "TrkGetSingleRecord",
  402. "Failed to open bug id for update" );
  403. return false;
  404. }
  405. rc = TrkUpdateRecordBegin( trkRecHandle );
  406. if ( rc != TRK_SUCCESS )
  407. {
  408. ReportError( rc, "TrkUpdateRecordBegin",
  409. "Failed to open bug id for update" );
  410. return false;
  411. }
  412. else
  413. {
  414. int textbuflen = 2 * buf.TellPut() + 1;
  415. char *textbuf = new char [ textbuflen ];
  416. Q_memset( textbuf, 0, textbuflen );
  417. SubstituteBugId( (int)bugId, textbuf, textbuflen, buf );
  418. // Update the description with the substituted text!!!
  419. rc = TrkSetDescriptionData( trkRecHandle,
  420. Q_strlen( textbuf ) + 1,
  421. (const char * )textbuf,
  422. 0 );
  423. delete[] textbuf;
  424. if ( rc != TRK_SUCCESS )
  425. {
  426. ReportError(rc, "TrkSetDescriptionData(update)",
  427. "Failed to set description data!");
  428. return false;
  429. }
  430. rc = TrkUpdateRecordCommit( trkRecHandle, &id );
  431. if ( rc != TRK_SUCCESS )
  432. {
  433. ReportError(rc, "TrkUpdateRecordCommit",
  434. "Failed to TrkUpdateRecordCommit for bug Id #!");
  435. return false;
  436. }
  437. }
  438. m_Fields.RemoveAll();
  439. return true;
  440. }
  441. SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
  442. {
  443. spewed = true;
  444. printf( "%s", pMsg );
  445. OutputDebugString( pMsg );
  446. if ( type == SPEW_ERROR )
  447. {
  448. printf( "\n" );
  449. OutputDebugString( "\n" );
  450. }
  451. return SPEW_CONTINUE;
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose:
  455. // Input : depth -
  456. // *fmt -
  457. // ... -
  458. //-----------------------------------------------------------------------------
  459. void vprint( int depth, const char *fmt, ... )
  460. {
  461. char string[ 8192 ];
  462. va_list va;
  463. va_start( va, fmt );
  464. vsprintf( string, fmt, va );
  465. va_end( va );
  466. FILE *fp = NULL;
  467. if ( uselogfile )
  468. {
  469. fp = fopen( "log.txt", "ab" );
  470. }
  471. while ( depth-- > 0 )
  472. {
  473. printf( " " );
  474. OutputDebugString( " " );
  475. if ( fp )
  476. {
  477. fprintf( fp, " " );
  478. }
  479. }
  480. ::printf( "%s", string );
  481. OutputDebugString( string );
  482. if ( fp )
  483. {
  484. char *p = string;
  485. while ( *p )
  486. {
  487. if ( *p == '\n' )
  488. {
  489. fputc( '\r', fp );
  490. }
  491. fputc( *p, fp );
  492. p++;
  493. }
  494. fclose( fp );
  495. }
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Purpose:
  499. //-----------------------------------------------------------------------------
  500. void printusage( void )
  501. {
  502. vprint( 0, "usage: getbugs pvcsproject hostname database username password contentadminexe <startbug endbug>\n\
  503. \ne.g.: getbugs \"Steam Beta\" steamweb cserr username password \"u:/p4clients/yahn_steam_work/projects/gazelleproto/tools/contentadmin/vc70_debug_static/contentadmin.exe\" 1 10\n" );
  504. // Exit app
  505. exit( 1 );
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose:
  509. //-----------------------------------------------------------------------------
  510. void CheckLogFile( void )
  511. {
  512. if ( uselogfile )
  513. {
  514. _unlink( "log.txt" );
  515. vprint( 0, " Outputting to log.txt\n" );
  516. }
  517. }
  518. void PrintHeader()
  519. {
  520. vprint( 0, "Valve Software - getbugs.exe (%s)\n", __DATE__ );
  521. vprint( 0, "--- Pulls public bugreporter bugs into PVCS tracker ---\n" );
  522. }
  523. bool GetBugZip( int bugnum, char const *admin )
  524. {
  525. bool retval = false;
  526. char commandline[ 512 ];
  527. char directory[ 512 ];
  528. Q_strncpy( directory, admin, sizeof( directory ) );
  529. Q_StripFilename( directory );
  530. // sprintf( commandline, "msdev engdll.dsw /MAKE \"quiver - Win32 GL Debug\" /OUT log.txt" );
  531. // Builds the default configuration
  532. sprintf( commandline, "\"%s\" bugreport %i", admin, bugnum );
  533. PROCESS_INFORMATION pi;
  534. memset( &pi, 0, sizeof( pi ) );
  535. STARTUPINFO si;
  536. memset( &si, 0, sizeof( si ) );
  537. si.cb = sizeof( si );
  538. if ( !CreateProcess( NULL, commandline, NULL, NULL, TRUE, 0, NULL, directory, &si, &pi ) )
  539. {
  540. LPVOID lpMsgBuf;
  541. FormatMessage(
  542. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  543. FORMAT_MESSAGE_FROM_SYSTEM |
  544. FORMAT_MESSAGE_IGNORE_INSERTS,
  545. NULL,
  546. GetLastError(),
  547. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  548. (LPTSTR) &lpMsgBuf,
  549. 0,
  550. NULL
  551. );
  552. // Process any inserts in lpMsgBuf.
  553. // ...
  554. // Display the string.
  555. MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION );
  556. // Free the buffer.
  557. LocalFree( lpMsgBuf );
  558. return retval;
  559. }
  560. // Wait until child process exits.
  561. WaitForSingleObject( pi.hProcess, INFINITE );
  562. DWORD exitCode = (DWORD)-1;
  563. if ( GetExitCodeProcess( pi.hProcess, &exitCode ) )
  564. {
  565. if ( exitCode == 0 )
  566. {
  567. retval = true;
  568. }
  569. }
  570. // Close process and thread handles.
  571. CloseHandle( pi.hProcess );
  572. CloseHandle( pi.hThread );
  573. return retval;
  574. }
  575. void CreateDirHierarchy(const char *path)
  576. {
  577. char temppath[512];
  578. Q_strncpy( temppath, path, sizeof(temppath) );
  579. for (char *ofs = temppath+1 ; *ofs ; ofs++)
  580. {
  581. if (*ofs == '/' || *ofs == '\\')
  582. { // create the directory
  583. char old = *ofs;
  584. *ofs = 0;
  585. _mkdir (temppath);
  586. *ofs = old;
  587. }
  588. }
  589. }
  590. void GetBugInfo( CBugReporter& bug, char const *host, char const *database, char const *username, char const *password, char const *admin, int startbug, int endbug )
  591. {
  592. // Now connect to steamweb and update the engineaccess table
  593. CSysModule *sql = Sys_LoadModule( "mysql_wrapper" );
  594. if ( sql )
  595. {
  596. CreateInterfaceFn factory = Sys_GetFactory( sql );
  597. if ( factory )
  598. {
  599. IMySQL *mysql = ( IMySQL * )factory( MYSQL_WRAPPER_VERSION_NAME, NULL );
  600. if ( mysql )
  601. {
  602. if ( mysql->InitMySQL( database, host, username, password ) )
  603. {
  604. char q[ 512 ];
  605. /*
  606. Q_snprintf( q, sizeof( q ), "insert into engineaccess (BuildIdentifier,AllowAccess) values (\"%s\",1);",
  607. argv[2] );
  608. int retcode = mysql->Execute( q );
  609. if ( retcode != 0 )
  610. {
  611. printf( "Query %s failed\n", q );
  612. }
  613. else
  614. {
  615. printf( "Successfully added buildidentifier '%s' to %s:%s\n",
  616. argv[ 2 ], argv[ 3 ], argv[ 4 ] );
  617. }
  618. */
  619. char where[ 256 ];
  620. where[ 0 ] = 0;
  621. if ( startbug != -1 && endbug != -1 )
  622. {
  623. Q_snprintf( where, sizeof( where ), "BugId>=%i and BugId<=%i and ", startbug, endbug );
  624. }
  625. Q_snprintf( q, sizeof( q ), "select BugId, Time, BuildNumber, ExeName, GameDirectory, MapName, Title, Description, IP,"
  626. "BaseIP, RAM, CPU, ProcessorVendor, DXVersionHighPart, DXVersionLowPart, DXVendorID, DXDeviceID, OSVersion, "
  627. "BugReportFilePath, ReportType, EMail, AccountName, SteamID, Processed, Important from bugreports where %s ( Processed is NULL or Processed = 0 );", where );
  628. int retcode = mysql->Execute( q );
  629. if ( retcode != 0 )
  630. {
  631. vprint( 0, "Query %s failed\n", q );
  632. }
  633. else
  634. {
  635. IMySQLRowSet *rows = mysql->DuplicateRowSet();
  636. CUtlVector< int > processed;
  637. if ( rows && rows->NumFields() > 0 )
  638. {
  639. while ( rows->NextRow() )
  640. {
  641. CColumnValue BugId = rows->GetColumnValue( "BugId" );
  642. CColumnValue Time = rows->GetColumnValue( "Time" );
  643. CColumnValue BuildNumber = rows->GetColumnValue( "BuildNumber" );
  644. CColumnValue ExeName = rows->GetColumnValue( "ExeName" );
  645. CColumnValue GameDirectory = rows->GetColumnValue( "GameDirectory" );
  646. CColumnValue MapName = rows->GetColumnValue( "MapName" );
  647. CColumnValue Title = rows->GetColumnValue( "Title" );
  648. CColumnValue Description = rows->GetColumnValue( "Description" );
  649. CColumnValue IP = rows->GetColumnValue( "IP" );
  650. CColumnValue BaseIP = rows->GetColumnValue( "BaseIP" );
  651. CColumnValue RAM = rows->GetColumnValue( "RAM" );
  652. CColumnValue CPU = rows->GetColumnValue( "CPU" );
  653. CColumnValue ProcessorVendor = rows->GetColumnValue( "ProcessorVendor" );
  654. CColumnValue DXVersionHighPart = rows->GetColumnValue( "DXVersionHighPart" );
  655. CColumnValue DXVersionLowPart = rows->GetColumnValue( "DXVersionLowPart" );
  656. CColumnValue DXVendorID = rows->GetColumnValue( "DXVendorID" );
  657. CColumnValue DXDeviceID = rows->GetColumnValue( "DXDeviceID" );
  658. CColumnValue OSVersion = rows->GetColumnValue( "OSVersion" );
  659. CColumnValue BugReportFilePath = rows->GetColumnValue( "BugReportFilePath" );
  660. CColumnValue ReportType = rows->GetColumnValue( "ReportType" );
  661. CColumnValue EMail = rows->GetColumnValue( "EMail" );
  662. CColumnValue Accountname = rows->GetColumnValue( "Accountname" );
  663. CColumnValue SteamID = rows->GetColumnValue( "SteamID" );
  664. CColumnValue Processed = rows->GetColumnValue( "Processed" );
  665. CColumnValue Important = rows->GetColumnValue( "Important" );
  666. bug.StartNewBugReport();
  667. vprint( 1, "Processing bug %i\n", BugId.Int32() );
  668. bug.AddField( "Owner", "PublicUser" );
  669. bug.AddField( "Submitter", "PublicUser" );
  670. bug.AddField( "Title", Title.String() );
  671. bug.AddNumericField( "BugId", BugId.Int32() );
  672. bug.AddNumericField( "Build", BuildNumber.Int32() );
  673. bug.AddField( "Exe", ExeName.String() );
  674. bug.AddField( "Gamedir", GameDirectory.String() );
  675. bug.AddField( "Map", MapName.String() );
  676. bug.AddField( "Operating System", OSVersion.String() );
  677. bug.AddField( "Processor", ProcessorVendor.String() );
  678. bug.AddNumericField( "Memory", RAM.Int32() );
  679. bug.AddField( "SteamID", SteamID.String() );
  680. bug.AddNumericField( "CPU", CPU.Int32() );
  681. bug.AddField( "Time", Time.String() );
  682. char dxversion[ 512 ];
  683. int vhigh = DXVersionHighPart.Int32();
  684. int vlow = DXVersionLowPart.Int32();
  685. Q_snprintf( dxversion, sizeof( dxversion ), "%u.%u.%u.%u", ( vhigh >> 16 ) , vhigh & 0xffff, ( vlow >> 16 ), vlow & 0xffff );
  686. bug.AddField( "DXVersion", dxversion);
  687. bug.AddNumericField( "DXDevice", DXDeviceID.Int32() );
  688. bug.AddNumericField( "DXVendor", DXVendorID.Int32() );
  689. bug.AddField( "BugType", ReportType.String() );
  690. bug.AddField( "E-Mail Address", EMail.String() );
  691. bug.AddField( "Account Name", Accountname.String() );
  692. char zipurl[ 512 ];
  693. zipurl[ 0 ] = 0;
  694. char basepath[ 512 ];
  695. Q_FileBase( BugReportFilePath.String(), basepath, sizeof( basepath ) );
  696. char desc[ 8192 ];
  697. if ( BugReportFilePath.String()[ 0 ] )
  698. {
  699. Q_snprintf( zipurl, sizeof( zipurl ), BUG_REPOSITORY_FMT, database, "BugId", basepath );
  700. Q_snprintf( desc, sizeof( desc ), "%s\n\nzip url: %s\n", Description.String(), zipurl );
  701. }
  702. else
  703. {
  704. Q_strncpy( desc, Description.String(), sizeof( desc ) );
  705. }
  706. bug.AddField( "Description", desc, true );
  707. int trackerBugId = -1;
  708. bool success = bug.CommitBugReport( trackerBugId );
  709. if ( success )
  710. {
  711. // The public UI handles uploading on it's own...
  712. // Fixup URL
  713. if ( zipurl[ 0 ] )
  714. {
  715. char zipurlfixed[ 512 ];
  716. char id[ 32 ];
  717. Q_snprintf( id, sizeof( id ), "%i", trackerBugId );
  718. // The upload destination
  719. Q_snprintf( zipurlfixed, sizeof( zipurlfixed ), BUG_REPOSITORY_FMT, database, id, basepath );
  720. Q_strlower( zipurlfixed );
  721. Q_FixSlashes( zipurlfixed );
  722. char admindir[ 512 ];
  723. Q_strncpy( admindir, admin, sizeof( admindir ) );
  724. Q_StripFilename( admindir );
  725. Q_strlower( admindir );
  726. Q_FixSlashes( admindir );
  727. char zipurllocal[ 512 ];
  728. Q_snprintf( zipurllocal, sizeof( zipurllocal ), "%s\\%s.zip", admindir, basepath );
  729. Q_strlower( zipurllocal );
  730. Q_FixSlashes( zipurllocal );
  731. // Get local copy of .zip file
  732. if ( GetBugZip( BugId.Int32(), admin ) )
  733. {
  734. struct _stat statbuf;
  735. if ( _stat( zipurllocal, &statbuf ) == 0 )
  736. {
  737. CreateDirHierarchy( zipurlfixed );
  738. MoveFile( zipurllocal, zipurlfixed );
  739. // Mark processed
  740. processed.AddToTail( BugId.Int32() );
  741. }
  742. }
  743. else
  744. {
  745. Warning( "Unable to retrieve bug file for %i\n", BugId.Int32() );
  746. }
  747. }
  748. else
  749. {
  750. processed.AddToTail( BugId.Int32() );
  751. }
  752. }
  753. else
  754. {
  755. Warning( "Unable to post bug report to database\n" );
  756. }
  757. }
  758. // Discard memory
  759. rows->Release();
  760. int c = processed.Count();
  761. for ( int i = 0; i < c; ++i )
  762. {
  763. Q_snprintf( q, sizeof( q ), "update bugreports set Processed=1 where BugId=%i;", processed[ i ] );
  764. retcode = mysql->Execute( q );
  765. if ( retcode != 0 )
  766. {
  767. Msg( "Query failed '%s'\n", q );
  768. }
  769. }
  770. }
  771. }
  772. }
  773. else
  774. {
  775. vprint( 0, "InitMySQL failed\n" );
  776. }
  777. mysql->Release();
  778. }
  779. else
  780. {
  781. vprint( 0, "Unable to connect via mysql_wrapper\n");
  782. }
  783. }
  784. else
  785. {
  786. vprint( 0, "Unable to get factory from mysql_wrapper.dll, not updating access mysql table!!!" );
  787. }
  788. Sys_UnloadModule( sql );
  789. }
  790. else
  791. {
  792. vprint( 0, "Unable to load mysql_wrapper.dll, not updating access mysql table!!!" );
  793. }
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Purpose:
  797. // Input : argc -
  798. // argv[] -
  799. // Output : int
  800. //-----------------------------------------------------------------------------
  801. int main( int argc, char* argv[] )
  802. {
  803. SpewOutputFunc( SpewFunc );
  804. SpewActivate( "getbugs", 2 );
  805. uselogfile = true;
  806. verbose = true;
  807. if ( argc != 7 && argc != 9 )
  808. {
  809. PrintHeader();
  810. printusage();
  811. }
  812. CheckLogFile();
  813. PrintHeader();
  814. vprint( 0, " Getting bugs...\n" );
  815. workingdir[0] = 0;
  816. Q_getwd( workingdir, sizeof( workingdir ) );
  817. // If they didn't specify -game on the command line, use VPROJECT.
  818. CmdLib_InitFileSystem( workingdir );
  819. CBugReporter bugreporter;
  820. if ( !bugreporter.Init( argv[ 1 ] ) )
  821. {
  822. vprint( 0, "Couldn't init bug reporter\n" );
  823. return 0;
  824. }
  825. if ( argc == 9 )
  826. {
  827. GetBugInfo( bugreporter, argv[2], argv[3], argv[4], argv[5], argv[ 6 ], atoi( argv[ 7 ] ), atoi( argv[ 8 ] ) );
  828. }
  829. else
  830. {
  831. GetBugInfo( bugreporter, argv[2], argv[3], argv[4], argv[5], argv[ 6 ], -1, -1 );
  832. }
  833. bugreporter.Shutdown();
  834. CmdLib_TermFileSystem();
  835. return 0;
  836. }