//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include #include #include "tier0/dbg.h" #include "utldict.h" #include "filesystem.h" #include "KeyValues.h" #include "cmdlib.h" #include "interface.h" #include "imysqlwrapper.h" #include "../bugreporter/trktool.h" #include "utlbuffer.h" #include #include #include bool uselogfile = false; static bool spewed = false; static char workingdir[ 256 ]; #define SCR_TYPE 1 #define DEFAULT_DBMS "tracker" #define DEFAULT_USERNAME "PublicUser" #define DEFAULT_PASSWORD DEFAULT_USERNAME #define BUG_REPOSITORY_FMT "\\\\fileserver\\bugs\\public\\%s\\%s\\%s.zip" struct BugField_t { BugField_t() { value[ 0 ] = 0; numvalue = 0; trkfield[ 0 ] = 0; isdesc = false; isnumeric = false; } char value[ 8192 ]; int numvalue; char trkfield[ 256 ]; bool isdesc; bool isnumeric; }; #define SQL_SETVALUE( fieldname, sqlcolumn ) Q_strncpy( bug.m_pBug->fieldname, sqlcolumn.String(), sizeof( bug.m_pBug->fieldname ) ); #define SQL_SETVALUESTRING( fieldname, str ) Q_strncpy( bug.m_pBug->fieldname, str, sizeof( bug.m_pBug->fieldname ) ); class CBugReporter { public: CBugReporter(); virtual ~CBugReporter(); // Initialize and login with default username/password for this computer (from resource/bugreporter.res) virtual bool Init( char const *projectname ); virtual void Shutdown(); virtual bool IsPublicUI() { return false; } // Submission API virtual void StartNewBugReport(); virtual void CancelNewBugReport(); virtual bool CommitBugReport( int& bugSubmissionId ); virtual void AddField( char const *fieldname, char const *value, bool isdesc = false ); virtual void AddNumericField( char const *fieldname, int value ); private: void ReportError(TRK_UINT rc, char const *func, char const *msg ); TRK_UINT Login(TRK_HANDLE* pTrkHandle, char const *projectname ); void SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src ); TRK_HANDLE trkHandle; TRK_RECORD_HANDLE trkRecHandle; public: CUtlVector< BugField_t > m_Fields; }; void CBugReporter::AddField( char const *fieldname, char const *value, bool isdesc /*=false*/ ) { BugField_t fld; Q_strncpy( fld.value, value, sizeof( fld.value ) ); fld.isnumeric = false; Q_strncpy( fld.trkfield, fieldname, sizeof( fld.trkfield ) ); fld.isdesc = isdesc; m_Fields.AddToTail( fld ); } void CBugReporter::AddNumericField( char const *fieldname, int value ) { BugField_t fld; fld.numvalue = value; fld.isnumeric = true; Q_strncpy( fld.trkfield, fieldname, sizeof( fld.trkfield ) ); fld.isdesc = false; m_Fields.AddToTail( fld ); } CBugReporter::CBugReporter() { trkHandle = (TRK_HANDLE)0; trkRecHandle = (TRK_RECORD_HANDLE)0; } CBugReporter::~CBugReporter() { m_Fields.RemoveAll(); } struct TRKELookup { unsigned int id; char const *str; }; #define TRKERROR( id ) { id, #id } static TRKELookup g_Lookup[] = { TRKERROR( TRK_SUCCESS ), TRKERROR( TRK_E_VERSION_MISMATCH ), TRKERROR( TRK_E_OUT_OF_MEMORY ), TRKERROR( TRK_E_BAD_HANDLE ), TRKERROR( TRK_E_BAD_INPUT_POINTER ), TRKERROR( TRK_E_BAD_INPUT_VALUE ), TRKERROR( TRK_E_DATA_TRUNCATED ), TRKERROR( TRK_E_NO_MORE_DATA ), TRKERROR( TRK_E_LIST_NOT_INITIALIZED ), TRKERROR( TRK_E_END_OF_LIST ), TRKERROR( TRK_E_NOT_LOGGED_IN ), TRKERROR( TRK_E_SERVER_NOT_PREPARED ), TRKERROR( TRK_E_BAD_DATABASE_VERSION ), TRKERROR( TRK_E_UNABLE_TO_CONNECT ), TRKERROR( TRK_E_UNABLE_TO_DISCONNECT ), TRKERROR( TRK_E_UNABLE_TO_START_TIMER ), TRKERROR( TRK_E_NO_DATA_SOURCES ), TRKERROR( TRK_E_NO_PROJECTS ), TRKERROR( TRK_E_WRITE_FAILED ), TRKERROR( TRK_E_PERMISSION_DENIED ), TRKERROR( TRK_E_SET_FIELD_DENIED ), TRKERROR( TRK_E_ITEM_NOT_FOUND ), TRKERROR( TRK_E_CANNOT_ACCESS_DATABASE ), TRKERROR( TRK_E_CANNOT_ACCESS_QUERY ), TRKERROR( TRK_E_CANNOT_ACCESS_INTRAY ), TRKERROR( TRK_E_CANNOT_OPEN_FILE ), TRKERROR( TRK_E_INVALID_DBMS_TYPE ), TRKERROR( TRK_E_INVALID_RECORD_TYPE ), TRKERROR( TRK_E_INVALID_FIELD ), TRKERROR( TRK_E_INVALID_CHOICE ), TRKERROR( TRK_E_INVALID_USER ), TRKERROR( TRK_E_INVALID_SUBMITTER ), TRKERROR( TRK_E_INVALID_OWNER ), TRKERROR( TRK_E_INVALID_DATE ), TRKERROR( TRK_E_INVALID_STORED_QUERY ), TRKERROR( TRK_E_INVALID_MODE ), TRKERROR( TRK_E_INVALID_MESSAGE ), TRKERROR( TRK_E_VALUE_OUT_OF_RANGE ), TRKERROR( TRK_E_WRONG_FIELD_TYPE ), TRKERROR( TRK_E_NO_CURRENT_RECORD ), TRKERROR( TRK_E_NO_CURRENT_NOTE ), TRKERROR( TRK_E_NO_CURRENT_ATTACHED_FILE ), TRKERROR( TRK_E_NO_CURRENT_ASSOCIATION ), TRKERROR( TRK_E_NO_RECORD_BEGIN ), TRKERROR( TRK_E_NO_MODULE ), TRKERROR( TRK_E_USER_CANCELLED ), TRKERROR( TRK_E_SEMAPHORE_TIMEOUT ), TRKERROR( TRK_E_SEMAPHORE_ERROR ), TRKERROR( TRK_E_INVALID_SERVER_NAME ), TRKERROR( TRK_E_NOT_LICENSED ) }; void CBugReporter::ReportError(TRK_UINT rc, char const *func, char const *msg ) { if ( rc != TRK_SUCCESS ) { switch (rc) { case TRK_E_ITEM_NOT_FOUND: Msg( "%s %s was not found!\n", func, msg ); break; case TRK_E_INVALID_FIELD: Msg( "%s %s Invalid field!\n", func, msg ); break; default: int i = 0; for ( i; i < ARRAYSIZE( g_Lookup ) ; ++i ) { if ( g_Lookup[ i ].id == rc ) { Msg( "%s returned %i - %s (%s)!\n", func, rc, g_Lookup[ i ].str, msg ); break; } } if ( i >= ARRAYSIZE( g_Lookup ) ) { Msg( "%s returned %i - %s! (%s)\n", func, rc, "???", msg ); } break; } } } TRK_UINT CBugReporter::Login(TRK_HANDLE* pTrkHandle, char const *projectname ) { char dbms[50] = DEFAULT_DBMS; char username[ 50 ]; char password[ 50 ]; Q_strncpy( username, DEFAULT_USERNAME, sizeof( username ) ); Q_strncpy( password, DEFAULT_PASSWORD, sizeof( password ) ); TRK_UINT rc = TrkProjectLogin(*pTrkHandle, username, password, projectname, NULL, NULL, NULL, NULL, TRK_USE_INI_FILE_DBMS_LOGIN); if (rc != TRK_SUCCESS) { rc = TrkProjectLogin(*pTrkHandle, username, "", projectname, NULL, NULL, NULL, NULL, TRK_USE_INI_FILE_DBMS_LOGIN); if (rc != TRK_SUCCESS) { Msg("Bug reporter init failed: Your tracker password must be your user name or blank.\n"); return rc; } } TrkGetLoginDBMSName(*pTrkHandle, sizeof(dbms), dbms ); char projout[ 256 ]; TrkGetLoginProjectName(*pTrkHandle, sizeof( projout ), projout ); Msg( "Project: %s\n", projout ); Msg( "Server: %s\n", dbms ); return rc; } //----------------------------------------------------------------------------- // Purpose: Initialize and login with default username/password for this computer (from resource/bugreporter.res) // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBugReporter::Init( char const *projectname ) { TRK_UINT rc; rc = TrkHandleAlloc( TRK_VERSION_ID, &trkHandle); if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkHandleAlloc", "Failed to Allocate Tracker Handle!"); return false; } // Login to default project out of INI file. rc = Login( &trkHandle, projectname ); if (rc != TRK_SUCCESS) { return false; } rc = TrkRecordHandleAlloc(trkHandle, &trkRecHandle); if (rc != TRK_SUCCESS) { ReportError(rc, "TrkRecordHandleAlloc", "Failed to Allocate Tracker Record Handle!"); return false; } return true; } void CBugReporter::Shutdown() { TRK_UINT rc; if ( trkRecHandle ) { rc = TrkRecordHandleFree(&trkRecHandle); if (rc != TRK_SUCCESS) { ReportError(rc, "TrkRecordHandleFree", "Failed to Free Tracker Record Handle!"); } } if ( trkHandle ) { rc = TrkProjectLogout(trkHandle); if (rc != TRK_SUCCESS) { ReportError(rc, "TrkProjectLogout", "Failed to Logout of Project!"); } else { rc = TrkHandleFree(&trkHandle); if (rc != TRK_SUCCESS) { ReportError(rc, "TrkHandleFree", "Failed to Free Tracker Handle!"); } } } } void CBugReporter::StartNewBugReport() { m_Fields.RemoveAll(); } void CBugReporter::CancelNewBugReport() { m_Fields.RemoveAll(); } void CBugReporter::SubstituteBugId( int bugid, char *out, int outlen, CUtlBuffer& src ) { out[ 0 ] = 0; char *dest = out; src.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); char const *replace = "\\BugId\\"; int replace_len = Q_strlen( replace ); for ( int pos = 0; pos <= src.TellPut() && ( ( dest - out ) < outlen ); ) { char const *str = ( char const * )src.PeekGet( pos ); if ( !Q_strnicmp( str, replace, replace_len ) ) { *dest++ = '\\'; char num[ 32 ]; Q_snprintf( num, sizeof( num ), "%i", bugid ); char *pnum = num; while ( *pnum ) { *dest++ = *pnum++; } *dest++ = '\\'; pos += replace_len; continue; } *dest++ = *str; ++pos; } *dest = 0; } bool CBugReporter::CommitBugReport( int& bugSubmissionId ) { bugSubmissionId = -1; int fieldCount = m_Fields.Count(); if ( fieldCount == 0 ) return false; TRK_UINT rc = 0; rc = TrkNewRecordBegin( trkRecHandle, SCR_TYPE ); if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkNewRecordBegin", "Failed to TrkNewRecordBegin!"); return false; } CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); for ( int i = 0; i < fieldCount; ++i ) { BugField_t& fld = m_Fields[ i ]; if ( !fld.isdesc ) { // Populate fields if ( !fld.isnumeric ) { rc = TrkSetStringFieldValue( trkRecHandle, fld.trkfield, fld.value ); } else { rc = TrkSetNumericFieldValue( trkRecHandle, fld.trkfield, fld.numvalue ); } if ( rc != TRK_SUCCESS ) { char es[ 256 ]; Q_snprintf( es, sizeof( es ), "Failed to add '%s'", fld.trkfield ); ReportError( rc, "TrkSetStringFieldValue", es ); return false; } } else { buf.Printf( "%s\n", fld.value ); buf.PutChar( 0 ); rc = TrkSetDescriptionData( trkRecHandle, buf.TellPut(), (const char * )buf.Base(), 0 ); if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkSetDescriptionData", "Failed to set description data!"); return false; } } } TRK_TRANSACTION_ID id; rc = TrkNewRecordCommit( trkRecHandle, &id ); if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkNewRecordCommit", "Failed to TrkNewRecordCommit!"); return false; } TRK_UINT bugId; rc = TrkGetNumericFieldValue( trkRecHandle, "Id", &bugId ); if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkGetNumericFieldValue", "Failed to TrkGetNumericFieldValue for bug Id #!"); } else { bugSubmissionId = (int)bugId; } rc = TrkGetSingleRecord( trkRecHandle, bugId, SCR_TYPE ); if ( rc != TRK_SUCCESS ) { ReportError( rc, "TrkGetSingleRecord", "Failed to open bug id for update" ); return false; } rc = TrkUpdateRecordBegin( trkRecHandle ); if ( rc != TRK_SUCCESS ) { ReportError( rc, "TrkUpdateRecordBegin", "Failed to open bug id for update" ); return false; } else { int textbuflen = 2 * buf.TellPut() + 1; char *textbuf = new char [ textbuflen ]; Q_memset( textbuf, 0, textbuflen ); SubstituteBugId( (int)bugId, textbuf, textbuflen, buf ); // Update the description with the substituted text!!! rc = TrkSetDescriptionData( trkRecHandle, Q_strlen( textbuf ) + 1, (const char * )textbuf, 0 ); delete[] textbuf; if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkSetDescriptionData(update)", "Failed to set description data!"); return false; } rc = TrkUpdateRecordCommit( trkRecHandle, &id ); if ( rc != TRK_SUCCESS ) { ReportError(rc, "TrkUpdateRecordCommit", "Failed to TrkUpdateRecordCommit for bug Id #!"); return false; } } m_Fields.RemoveAll(); return true; } SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg ) { spewed = true; printf( "%s", pMsg ); OutputDebugString( pMsg ); if ( type == SPEW_ERROR ) { printf( "\n" ); OutputDebugString( "\n" ); } return SPEW_CONTINUE; } //----------------------------------------------------------------------------- // Purpose: // Input : depth - // *fmt - // ... - //----------------------------------------------------------------------------- void vprint( int depth, const char *fmt, ... ) { char string[ 8192 ]; va_list va; va_start( va, fmt ); vsprintf( string, fmt, va ); va_end( va ); FILE *fp = NULL; if ( uselogfile ) { fp = fopen( "log.txt", "ab" ); } while ( depth-- > 0 ) { printf( " " ); OutputDebugString( " " ); if ( fp ) { fprintf( fp, " " ); } } ::printf( "%s", string ); OutputDebugString( string ); if ( fp ) { char *p = string; while ( *p ) { if ( *p == '\n' ) { fputc( '\r', fp ); } fputc( *p, fp ); p++; } fclose( fp ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void printusage( void ) { vprint( 0, "usage: getbugs pvcsproject hostname database username password contentadminexe \n\ \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" ); // Exit app exit( 1 ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CheckLogFile( void ) { if ( uselogfile ) { _unlink( "log.txt" ); vprint( 0, " Outputting to log.txt\n" ); } } void PrintHeader() { vprint( 0, "Valve Software - getbugs.exe (%s)\n", __DATE__ ); vprint( 0, "--- Pulls public bugreporter bugs into PVCS tracker ---\n" ); } bool GetBugZip( int bugnum, char const *admin ) { bool retval = false; char commandline[ 512 ]; char directory[ 512 ]; Q_strncpy( directory, admin, sizeof( directory ) ); Q_StripFilename( directory ); // sprintf( commandline, "msdev engdll.dsw /MAKE \"quiver - Win32 GL Debug\" /OUT log.txt" ); // Builds the default configuration sprintf( commandline, "\"%s\" bugreport %i", admin, bugnum ); PROCESS_INFORMATION pi; memset( &pi, 0, sizeof( pi ) ); STARTUPINFO si; memset( &si, 0, sizeof( si ) ); si.cb = sizeof( si ); if ( !CreateProcess( NULL, commandline, NULL, NULL, TRUE, 0, NULL, directory, &si, &pi ) ) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL ); // Process any inserts in lpMsgBuf. // ... // Display the string. MessageBox( NULL, (LPCTSTR)lpMsgBuf, "Error", MB_OK | MB_ICONINFORMATION ); // Free the buffer. LocalFree( lpMsgBuf ); return retval; } // Wait until child process exits. WaitForSingleObject( pi.hProcess, INFINITE ); DWORD exitCode = (DWORD)-1; if ( GetExitCodeProcess( pi.hProcess, &exitCode ) ) { if ( exitCode == 0 ) { retval = true; } } // Close process and thread handles. CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); return retval; } void CreateDirHierarchy(const char *path) { char temppath[512]; Q_strncpy( temppath, path, sizeof(temppath) ); for (char *ofs = temppath+1 ; *ofs ; ofs++) { if (*ofs == '/' || *ofs == '\\') { // create the directory char old = *ofs; *ofs = 0; _mkdir (temppath); *ofs = old; } } } void GetBugInfo( CBugReporter& bug, char const *host, char const *database, char const *username, char const *password, char const *admin, int startbug, int endbug ) { // Now connect to steamweb and update the engineaccess table CSysModule *sql = Sys_LoadModule( "mysql_wrapper" ); if ( sql ) { CreateInterfaceFn factory = Sys_GetFactory( sql ); if ( factory ) { IMySQL *mysql = ( IMySQL * )factory( MYSQL_WRAPPER_VERSION_NAME, NULL ); if ( mysql ) { if ( mysql->InitMySQL( database, host, username, password ) ) { char q[ 512 ]; /* Q_snprintf( q, sizeof( q ), "insert into engineaccess (BuildIdentifier,AllowAccess) values (\"%s\",1);", argv[2] ); int retcode = mysql->Execute( q ); if ( retcode != 0 ) { printf( "Query %s failed\n", q ); } else { printf( "Successfully added buildidentifier '%s' to %s:%s\n", argv[ 2 ], argv[ 3 ], argv[ 4 ] ); } */ char where[ 256 ]; where[ 0 ] = 0; if ( startbug != -1 && endbug != -1 ) { Q_snprintf( where, sizeof( where ), "BugId>=%i and BugId<=%i and ", startbug, endbug ); } Q_snprintf( q, sizeof( q ), "select BugId, Time, BuildNumber, ExeName, GameDirectory, MapName, Title, Description, IP," "BaseIP, RAM, CPU, ProcessorVendor, DXVersionHighPart, DXVersionLowPart, DXVendorID, DXDeviceID, OSVersion, " "BugReportFilePath, ReportType, EMail, AccountName, SteamID, Processed, Important from bugreports where %s ( Processed is NULL or Processed = 0 );", where ); int retcode = mysql->Execute( q ); if ( retcode != 0 ) { vprint( 0, "Query %s failed\n", q ); } else { IMySQLRowSet *rows = mysql->DuplicateRowSet(); CUtlVector< int > processed; if ( rows && rows->NumFields() > 0 ) { while ( rows->NextRow() ) { CColumnValue BugId = rows->GetColumnValue( "BugId" ); CColumnValue Time = rows->GetColumnValue( "Time" ); CColumnValue BuildNumber = rows->GetColumnValue( "BuildNumber" ); CColumnValue ExeName = rows->GetColumnValue( "ExeName" ); CColumnValue GameDirectory = rows->GetColumnValue( "GameDirectory" ); CColumnValue MapName = rows->GetColumnValue( "MapName" ); CColumnValue Title = rows->GetColumnValue( "Title" ); CColumnValue Description = rows->GetColumnValue( "Description" ); CColumnValue IP = rows->GetColumnValue( "IP" ); CColumnValue BaseIP = rows->GetColumnValue( "BaseIP" ); CColumnValue RAM = rows->GetColumnValue( "RAM" ); CColumnValue CPU = rows->GetColumnValue( "CPU" ); CColumnValue ProcessorVendor = rows->GetColumnValue( "ProcessorVendor" ); CColumnValue DXVersionHighPart = rows->GetColumnValue( "DXVersionHighPart" ); CColumnValue DXVersionLowPart = rows->GetColumnValue( "DXVersionLowPart" ); CColumnValue DXVendorID = rows->GetColumnValue( "DXVendorID" ); CColumnValue DXDeviceID = rows->GetColumnValue( "DXDeviceID" ); CColumnValue OSVersion = rows->GetColumnValue( "OSVersion" ); CColumnValue BugReportFilePath = rows->GetColumnValue( "BugReportFilePath" ); CColumnValue ReportType = rows->GetColumnValue( "ReportType" ); CColumnValue EMail = rows->GetColumnValue( "EMail" ); CColumnValue Accountname = rows->GetColumnValue( "Accountname" ); CColumnValue SteamID = rows->GetColumnValue( "SteamID" ); CColumnValue Processed = rows->GetColumnValue( "Processed" ); CColumnValue Important = rows->GetColumnValue( "Important" ); bug.StartNewBugReport(); vprint( 1, "Processing bug %i\n", BugId.Int32() ); bug.AddField( "Owner", "PublicUser" ); bug.AddField( "Submitter", "PublicUser" ); bug.AddField( "Title", Title.String() ); bug.AddNumericField( "BugId", BugId.Int32() ); bug.AddNumericField( "Build", BuildNumber.Int32() ); bug.AddField( "Exe", ExeName.String() ); bug.AddField( "Gamedir", GameDirectory.String() ); bug.AddField( "Map", MapName.String() ); bug.AddField( "Operating System", OSVersion.String() ); bug.AddField( "Processor", ProcessorVendor.String() ); bug.AddNumericField( "Memory", RAM.Int32() ); bug.AddField( "SteamID", SteamID.String() ); bug.AddNumericField( "CPU", CPU.Int32() ); bug.AddField( "Time", Time.String() ); char dxversion[ 512 ]; int vhigh = DXVersionHighPart.Int32(); int vlow = DXVersionLowPart.Int32(); Q_snprintf( dxversion, sizeof( dxversion ), "%u.%u.%u.%u", ( vhigh >> 16 ) , vhigh & 0xffff, ( vlow >> 16 ), vlow & 0xffff ); bug.AddField( "DXVersion", dxversion); bug.AddNumericField( "DXDevice", DXDeviceID.Int32() ); bug.AddNumericField( "DXVendor", DXVendorID.Int32() ); bug.AddField( "BugType", ReportType.String() ); bug.AddField( "E-Mail Address", EMail.String() ); bug.AddField( "Account Name", Accountname.String() ); char zipurl[ 512 ]; zipurl[ 0 ] = 0; char basepath[ 512 ]; Q_FileBase( BugReportFilePath.String(), basepath, sizeof( basepath ) ); char desc[ 8192 ]; if ( BugReportFilePath.String()[ 0 ] ) { Q_snprintf( zipurl, sizeof( zipurl ), BUG_REPOSITORY_FMT, database, "BugId", basepath ); Q_snprintf( desc, sizeof( desc ), "%s\n\nzip url: %s\n", Description.String(), zipurl ); } else { Q_strncpy( desc, Description.String(), sizeof( desc ) ); } bug.AddField( "Description", desc, true ); int trackerBugId = -1; bool success = bug.CommitBugReport( trackerBugId ); if ( success ) { // The public UI handles uploading on it's own... // Fixup URL if ( zipurl[ 0 ] ) { char zipurlfixed[ 512 ]; char id[ 32 ]; Q_snprintf( id, sizeof( id ), "%i", trackerBugId ); // The upload destination Q_snprintf( zipurlfixed, sizeof( zipurlfixed ), BUG_REPOSITORY_FMT, database, id, basepath ); Q_strlower( zipurlfixed ); Q_FixSlashes( zipurlfixed ); char admindir[ 512 ]; Q_strncpy( admindir, admin, sizeof( admindir ) ); Q_StripFilename( admindir ); Q_strlower( admindir ); Q_FixSlashes( admindir ); char zipurllocal[ 512 ]; Q_snprintf( zipurllocal, sizeof( zipurllocal ), "%s\\%s.zip", admindir, basepath ); Q_strlower( zipurllocal ); Q_FixSlashes( zipurllocal ); // Get local copy of .zip file if ( GetBugZip( BugId.Int32(), admin ) ) { struct _stat statbuf; if ( _stat( zipurllocal, &statbuf ) == 0 ) { CreateDirHierarchy( zipurlfixed ); MoveFile( zipurllocal, zipurlfixed ); // Mark processed processed.AddToTail( BugId.Int32() ); } } else { Warning( "Unable to retrieve bug file for %i\n", BugId.Int32() ); } } else { processed.AddToTail( BugId.Int32() ); } } else { Warning( "Unable to post bug report to database\n" ); } } // Discard memory rows->Release(); int c = processed.Count(); for ( int i = 0; i < c; ++i ) { Q_snprintf( q, sizeof( q ), "update bugreports set Processed=1 where BugId=%i;", processed[ i ] ); retcode = mysql->Execute( q ); if ( retcode != 0 ) { Msg( "Query failed '%s'\n", q ); } } } } } else { vprint( 0, "InitMySQL failed\n" ); } mysql->Release(); } else { vprint( 0, "Unable to connect via mysql_wrapper\n"); } } else { vprint( 0, "Unable to get factory from mysql_wrapper.dll, not updating access mysql table!!!" ); } Sys_UnloadModule( sql ); } else { vprint( 0, "Unable to load mysql_wrapper.dll, not updating access mysql table!!!" ); } } //----------------------------------------------------------------------------- // Purpose: // Input : argc - // argv[] - // Output : int //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { SpewOutputFunc( SpewFunc ); SpewActivate( "getbugs", 2 ); uselogfile = true; verbose = true; if ( argc != 7 && argc != 9 ) { PrintHeader(); printusage(); } CheckLogFile(); PrintHeader(); vprint( 0, " Getting bugs...\n" ); workingdir[0] = 0; Q_getwd( workingdir, sizeof( workingdir ) ); // If they didn't specify -game on the command line, use VPROJECT. CmdLib_InitFileSystem( workingdir ); CBugReporter bugreporter; if ( !bugreporter.Init( argv[ 1 ] ) ) { vprint( 0, "Couldn't init bug reporter\n" ); return 0; } if ( argc == 9 ) { GetBugInfo( bugreporter, argv[2], argv[3], argv[4], argv[5], argv[ 6 ], atoi( argv[ 7 ] ), atoi( argv[ 8 ] ) ); } else { GetBugInfo( bugreporter, argv[2], argv[3], argv[4], argv[5], argv[ 6 ], -1, -1 ); } bugreporter.Shutdown(); CmdLib_TermFileSystem(); return 0; }