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
922 lines
23 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
//#define PROTECTED_THINGS_DISABLE |
|
#undef PROTECT_FILEIO_FUNCTIONS |
|
#undef fopen |
|
#include "winlite.h" |
|
#include <time.h> |
|
#ifdef WIN32 |
|
#include <io.h> |
|
#include <direct.h> |
|
#else |
|
#include <sys/stat.h> |
|
#define _stat stat |
|
#endif |
|
#include <stdio.h> |
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
|
|
#include "basetypes.h" |
|
|
|
#include "utlvector.h" |
|
#include "utlsymbol.h" |
|
#include "utldict.h" |
|
#include "utlbuffer.h" |
|
#include "utlmap.h" |
|
|
|
#include "bugreporter/bugreporter.h" |
|
#include "filesystem_tools.h" |
|
#include "KeyValues.h" |
|
#include "vstdlib/random.h" |
|
|
|
#ifdef WIN32 |
|
#define BUGSUB_CONFIG "\\\\bugbait\\bugsub\\config.txt" |
|
#else |
|
#ifdef OSX |
|
#define BUGSUB_CONFIG "/Volumes/bugsub/config.txt" |
|
#define BUGSUB_MOUNT "/Volumes/bugsub" |
|
#define BUGSUB_MOUNT_COMMAND "mount_smbfs //guest:@bugbait.valvesoftware.com/bugsub " BUGSUB_MOUNT |
|
#else |
|
// We can't do sudo here, so we rely on /etc/fstab being setup for '/mnt/bugsub'. See comment in CBugReporter::Init(). |
|
#define BUGSUB_CONFIG "/mnt/bugsub/config.txt" |
|
#define BUGSUB_MOUNT "/mnt/bugsub" |
|
#define BUGSUB_MOUNT_COMMAND "mount /mnt/bugsub" |
|
#endif |
|
#define BUGSUB_UNMOUNT_COMMAND "umount " BUGSUB_MOUNT |
|
#endif |
|
|
|
class CBugReporter *g_bugreporter = NULL; |
|
|
|
class CBug |
|
{ |
|
public: |
|
CBug() |
|
{ |
|
Clear(); |
|
} |
|
|
|
void Clear() |
|
{ |
|
Q_memset( title, 0, sizeof( title ) ); |
|
Q_memset( desc, 0, sizeof( desc ) ); |
|
Q_memset( submitter, 0, sizeof( submitter ) ); |
|
Q_memset( owner, 0, sizeof( owner ) ); |
|
Q_memset( severity, 0, sizeof( severity ) ); |
|
Q_memset( priority, 0, sizeof( priority ) ); |
|
Q_memset( area, 0, sizeof( area ) ); |
|
Q_memset( mapnumber, 0, sizeof( mapnumber) ); |
|
Q_memset( reporttype, 0, sizeof( reporttype ) ); |
|
Q_memset( level, 0, sizeof( level ) ); |
|
Q_memset( build, 0, sizeof( build ) ); |
|
Q_memset( position, 0, sizeof( position ) ); |
|
Q_memset( orientation, 0, sizeof( orientation ) ); |
|
Q_memset( screenshot_unc, 0, sizeof( screenshot_unc ) ); |
|
Q_memset( savegame_unc, 0, sizeof( savegame_unc ) ); |
|
Q_memset( bsp_unc, 0, sizeof( bsp_unc ) ); |
|
Q_memset( vmf_unc, 0, sizeof( vmf_unc ) ); |
|
Q_memset( driverinfo, 0, sizeof( driverinfo ) ); |
|
Q_memset( misc, 0, sizeof( misc ) ); |
|
|
|
includedfiles.Purge(); |
|
} |
|
|
|
char title[ 256 ]; |
|
char desc[ 8192 ]; |
|
char owner[ 256 ]; |
|
char submitter[ 256 ]; |
|
char severity[ 256 ]; |
|
char priority[ 256 ]; |
|
char area[ 256 ]; |
|
char mapnumber[ 256 ]; |
|
char reporttype[ 256 ]; |
|
char level[ 256 ]; |
|
char build[ 256 ]; |
|
char position[ 256 ]; |
|
char orientation[ 256 ]; |
|
char screenshot_unc[ 256 ]; |
|
char savegame_unc[ 256 ]; |
|
char bsp_unc[ 256 ]; |
|
char vmf_unc[ 256 ]; |
|
char driverinfo[ 2048 ]; |
|
char misc[ 1024 ]; |
|
|
|
struct incfile |
|
{ |
|
char name[ 256 ]; |
|
}; |
|
|
|
CUtlVector< incfile > includedfiles; |
|
}; |
|
|
|
class CBugReporter : public IBugReporter |
|
{ |
|
public: |
|
|
|
CBugReporter(); |
|
virtual ~CBugReporter(); |
|
|
|
// Initialize and login with default username/password for this computer (from resource/bugreporter.res) |
|
virtual bool Init( CreateInterfaceFn engineFactory ); |
|
virtual void Shutdown(); |
|
|
|
virtual bool IsPublicUI() { return false; } |
|
|
|
virtual char const *GetUserName(); |
|
virtual char const *GetUserName_Display(); |
|
|
|
virtual int GetNameCount(); |
|
virtual char const *GetName( int index ); |
|
|
|
virtual int GetDisplayNameCount(); |
|
virtual char const *GetDisplayName( int index ); |
|
virtual char const *GetUserNameForIndex( int index ); |
|
|
|
virtual char const *GetDisplayNameForUserName( char const *username ); |
|
virtual char const *GetUserNameForDisplayName( char const *display ); |
|
virtual char const *GetAreaMapForArea( char const * area); |
|
|
|
virtual int GetSeverityCount(); |
|
virtual char const *GetSeverity( int index ); |
|
|
|
virtual int GetPriorityCount(); |
|
virtual char const *GetPriority( int index ); |
|
|
|
virtual int GetAreaCount(); |
|
virtual char const *GetArea( int index ); |
|
|
|
virtual int GetAreaMapCount(); |
|
virtual char const *GetAreaMap( int index ); |
|
|
|
virtual int GetMapNumberCount(); |
|
virtual char const *GetMapNumber( int index ); |
|
|
|
virtual int GetReportTypeCount(); |
|
virtual char const *GetReportType( int index ); |
|
|
|
virtual char const *GetRepositoryURL( void ); |
|
virtual char const *GetSubmissionURL( void ); |
|
|
|
virtual int GetLevelCount(int area); |
|
virtual char const *GetLevel(int area, int index ); |
|
|
|
// Submission API |
|
virtual void StartNewBugReport(); |
|
virtual void CancelNewBugReport(); |
|
virtual bool CommitBugReport( int& bugSubmissionId ); |
|
|
|
virtual void SetTitle( char const *title ); |
|
virtual void SetDescription( char const *description ); |
|
|
|
// NULL for current user |
|
virtual void SetSubmitter( char const *username = 0 ); |
|
virtual void SetOwner( char const *username ); |
|
virtual void SetSeverity( char const *severity ); |
|
virtual void SetPriority( char const *priority ); |
|
virtual void SetArea( char const *area ); |
|
virtual void SetMapNumber ( char const *mapnumber ); |
|
virtual void SetReportType( char const *reporttype ); |
|
|
|
virtual void SetLevel( char const *levelnamne ); |
|
virtual void SetPosition( char const *position ); |
|
virtual void SetOrientation( char const *pitch_yaw_roll ); |
|
virtual void SetBuildNumber( char const *build_num ); |
|
|
|
virtual void SetScreenShot( char const *screenshot_unc_address ); |
|
virtual void SetSaveGame( char const *savegame_unc_address ); |
|
|
|
virtual void SetBSPName( char const *bsp_unc_address ); |
|
virtual void SetVMFName( char const *vmf_unc_address ); |
|
|
|
virtual void AddIncludedFile( char const *filename ); |
|
virtual void ResetIncludedFiles(); |
|
|
|
virtual void SetZipAttachmentName( char const *zipfilename ) {} // only used by public bug reporter |
|
|
|
virtual void SetDriverInfo( char const *info ); |
|
|
|
virtual void SetMiscInfo( char const *info ); |
|
|
|
// These are stubbed here, but are used by the public version... |
|
virtual void SetCSERAddress( const struct netadr_s& adr ) {} |
|
virtual void SetExeName( char const *exename ) {} |
|
virtual void SetGameDirectory( char const *pchGamedir ) {} |
|
virtual void SetRAM( int ram ) {} |
|
virtual void SetCPU( int cpu ) {} |
|
virtual void SetProcessor( char const *processor ) {} |
|
virtual void SetDXVersion( unsigned int high, unsigned int low, unsigned int vendor, unsigned int device ) {} |
|
virtual void SetOSVersion( char const *osversion ) {} |
|
virtual void SetSteamUserID( void *steamid, int idsize ) {}; |
|
bool SymbolLessThan(const CUtlSymbol &sym1, const CUtlSymbol &sym2); |
|
|
|
private: |
|
|
|
bool PopulateLists(); |
|
bool PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list ); |
|
|
|
CUtlSymbolTable m_BugStrings; |
|
|
|
CUtlVector< CUtlSymbol > m_Severity; |
|
CUtlVector< CUtlSymbol > m_SortedDisplayNames; |
|
CUtlVector< CUtlSymbol > m_SortedUserNames; |
|
CUtlVector< CUtlSymbol > m_Priority; |
|
CUtlVector< CUtlSymbol > m_Area; |
|
CUtlVector< CUtlSymbol > m_AreaMap; |
|
CUtlVector< CUtlSymbol > m_MapNumber; |
|
CUtlVector< CUtlSymbol > m_ReportType; |
|
CUtlMap<CUtlSymbol, CUtlVector< CUtlSymbol > *> m_LevelMap; |
|
|
|
CUtlSymbol m_UserName; |
|
|
|
CBug *m_pBug; |
|
|
|
char m_BugRootDirectory[512]; |
|
KeyValues *m_OptionsFile; |
|
|
|
int m_CurrentBugID; |
|
char m_CurrentBugDirectory[512]; |
|
bool m_bMountedBugSub; |
|
}; |
|
|
|
bool CUtlSymbol_LessThan(const CUtlSymbol &sym1, const CUtlSymbol &sym2) |
|
{ |
|
return g_bugreporter->SymbolLessThan(sym1, sym2); |
|
} |
|
|
|
CBugReporter::CBugReporter() |
|
{ |
|
m_pBug = NULL; |
|
m_CurrentBugID = 0; |
|
m_bMountedBugSub = false; |
|
m_LevelMap.SetLessFunc(&CUtlSymbol_LessThan); |
|
g_bugreporter = this; |
|
} |
|
|
|
CBugReporter::~CBugReporter() |
|
{ |
|
m_BugStrings.RemoveAll(); |
|
m_Severity.Purge(); |
|
m_SortedDisplayNames.Purge(); |
|
m_Priority.Purge(); |
|
m_Area.Purge(); |
|
m_MapNumber.Purge(); |
|
m_ReportType.Purge(); |
|
m_LevelMap.RemoveAll(); |
|
|
|
delete m_pBug; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// 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( CreateInterfaceFn engineFactory ) |
|
{ |
|
// Load our bugreporter_text options file |
|
m_OptionsFile = new KeyValues( "OptionsFile" ); |
|
|
|
#ifdef POSIX |
|
// check if we can see the config file |
|
struct _stat mount_info; |
|
if (_stat(BUGSUB_CONFIG, &mount_info)) |
|
{ |
|
// if not we may need to mount bugbait |
|
if ( _stat(BUGSUB_MOUNT, &mount_info ) ) |
|
{ |
|
// make the mount dir if needed |
|
mkdir( BUGSUB_MOUNT, S_IRWXU | S_IRWXG | S_IRWXO ); |
|
} |
|
|
|
// now run the smbmount on it |
|
system( BUGSUB_MOUNT_COMMAND ); |
|
|
|
#ifdef LINUX |
|
if( _stat( BUGSUB_CONFIG, &mount_info ) ) |
|
{ |
|
Color clr( 255, 100, 50, 255 ); |
|
|
|
// The mount failed - probably because the /etc/fstab entry is missing? |
|
ConColorMsg( clr, "ERROR: failed to mount '" BUGSUB_MOUNT "' with '" BUGSUB_MOUNT_COMMAND "'.\n" ); |
|
ConColorMsg( clr, "Bugsub not set up yet? Do 'sudo apt-get install smbfs', 'sudo mkdir /mnt/bugsub', and add this /etc/fstab:\n" ); |
|
ConColorMsg( clr, " bugbait.valvesoftware.com/bugsub /mnt/bugsub smbfs rw,user,username=guest,password=,noauto 0 0\n" ); |
|
return false; |
|
} |
|
#endif |
|
|
|
m_bMountedBugSub = true; |
|
} |
|
|
|
#elif defined(WIN32) |
|
|
|
#else |
|
#error "need to get to \\bugbait somehow" |
|
#endif |
|
|
|
// open file old skool way to avoid steam filesystem restrictions |
|
struct _stat cfg_info; |
|
if (_stat(BUGSUB_CONFIG, &cfg_info)) { |
|
AssertMsg( 0, "Failed to find bugreporter options file." ); |
|
return false; |
|
} |
|
|
|
int buf_size = (cfg_info.st_size + 1); |
|
char *buf = new char[buf_size]; |
|
FILE *fp = fopen(BUGSUB_CONFIG, "rb"); |
|
if (!fp) { |
|
AssertMsg(0, "failed to open bugreporter options file" ); |
|
delete [] buf; |
|
return false; |
|
} |
|
|
|
fread(buf, cfg_info.st_size, 1, fp); |
|
fclose(fp); |
|
buf[cfg_info.st_size] = 0; |
|
if ( !m_OptionsFile->LoadFromBuffer(BUGSUB_CONFIG, buf) ) |
|
{ |
|
AssertMsg( 0, "Failed to load bugreporter_text options file." ); |
|
delete [] buf; |
|
return false; |
|
} |
|
#ifdef WIN32 |
|
V_strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory", "." ), sizeof(m_BugRootDirectory) ); |
|
#elif defined(OSX) |
|
V_strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory_osx", BUGSUB_MOUNT ), sizeof(m_BugRootDirectory) ); |
|
#elif defined(LINUX) |
|
V_strncpy( m_BugRootDirectory, m_OptionsFile->GetString( "bug_directory_linux", BUGSUB_MOUNT ), sizeof(m_BugRootDirectory) ); |
|
#else |
|
#error |
|
#endif |
|
|
|
PopulateLists(); |
|
|
|
#ifdef WIN32 |
|
m_UserName = m_BugStrings.AddString(getenv( "username" )); |
|
#elif POSIX |
|
m_UserName = m_BugStrings.AddString(getenv( "USER" )); |
|
#else |
|
#error |
|
#endif |
|
delete [] buf; |
|
return true; |
|
} |
|
|
|
void CBugReporter::Shutdown() |
|
{ |
|
#ifdef POSIX |
|
if ( m_bMountedBugSub ) |
|
{ |
|
system( BUGSUB_UNMOUNT_COMMAND ); |
|
} |
|
#endif |
|
} |
|
|
|
char const *CBugReporter::GetUserName() |
|
{ |
|
return m_BugStrings.String( m_UserName ); |
|
} |
|
|
|
char const *CBugReporter::GetUserName_Display() |
|
{ |
|
return GetDisplayNameForUserName( GetUserName() ); |
|
} |
|
|
|
int CBugReporter::GetNameCount() |
|
{ |
|
return GetDisplayNameCount(); |
|
} |
|
|
|
char const *CBugReporter::GetName( int index ) |
|
{ |
|
return GetDisplayName(index); |
|
} |
|
|
|
int CBugReporter::GetDisplayNameCount() |
|
{ |
|
return m_SortedDisplayNames.Count(); |
|
} |
|
|
|
char const *CBugReporter::GetDisplayName( int index ) |
|
{ |
|
if ( index < 0 || index >= (int)m_SortedDisplayNames.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_SortedDisplayNames[ index ] ); |
|
} |
|
|
|
char const *CBugReporter::GetUserNameForIndex( int index ) |
|
{ |
|
if ( index < 0 || index >= (int)m_SortedUserNames.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_SortedUserNames[ index ] ); |
|
} |
|
|
|
char const *CBugReporter::GetDisplayNameForUserName( char const *username ) |
|
{ |
|
CUtlSymbol username_sym = m_BugStrings.Find(username); |
|
FOR_EACH_VEC(m_SortedUserNames, index) { |
|
if (m_SortedUserNames[index] == username_sym) { |
|
return GetDisplayName(index); |
|
} |
|
} |
|
return username; |
|
} |
|
|
|
char const *CBugReporter::GetUserNameForDisplayName( char const *display ) |
|
{ |
|
CUtlSymbol display_sym = m_BugStrings.Find(display); |
|
FOR_EACH_VEC(m_SortedDisplayNames, index) { |
|
if (m_SortedDisplayNames[index] == display_sym) { |
|
return GetUserNameForIndex(index); |
|
} |
|
} |
|
|
|
return display; |
|
} |
|
|
|
char const *CBugReporter::GetAreaMapForArea( char const *area) |
|
{ |
|
CUtlSymbol area_sym = m_BugStrings.Find(area); |
|
FOR_EACH_VEC(m_Area, index) { |
|
if (m_Area[index] == area_sym && index > 0) { |
|
char const *areamap = m_BugStrings.String(m_AreaMap[index-1]); |
|
return areamap+1; |
|
} |
|
} |
|
|
|
return "<<Invalid>>"; |
|
} |
|
|
|
int CBugReporter::GetSeverityCount() |
|
{ |
|
return m_Severity.Count() ; |
|
} |
|
|
|
char const *CBugReporter::GetSeverity( int index ) |
|
{ |
|
if ( index < 0 || index >= m_Severity.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_Severity[ index ] ); |
|
} |
|
|
|
int CBugReporter::GetPriorityCount() |
|
{ |
|
return m_Priority.Count(); |
|
} |
|
|
|
char const *CBugReporter::GetPriority( int index ) |
|
{ |
|
if ( index < 0 || index >= m_Priority.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_Priority[ index ] ); |
|
} |
|
|
|
int CBugReporter::GetAreaCount() |
|
{ |
|
return m_Area.Count(); |
|
} |
|
|
|
char const *CBugReporter::GetArea( int index ) |
|
{ |
|
if ( index < 0 || index >= m_Area.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_Area[ index ] ); |
|
} |
|
|
|
int CBugReporter::GetAreaMapCount() |
|
{ |
|
return m_AreaMap.Count(); |
|
} |
|
|
|
char const *CBugReporter::GetAreaMap( int index ) |
|
{ |
|
if ( index < 0 || index >= m_AreaMap.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_AreaMap[ index ] ); |
|
} |
|
|
|
int CBugReporter::GetMapNumberCount() |
|
{ |
|
return m_MapNumber.Count(); |
|
} |
|
|
|
char const *CBugReporter::GetMapNumber( int index ) |
|
{ |
|
if ( index < 0 || index >= m_MapNumber.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_MapNumber[ index ] ); |
|
} |
|
|
|
int CBugReporter::GetReportTypeCount() |
|
{ |
|
return m_ReportType.Count(); |
|
} |
|
|
|
char const *CBugReporter::GetReportType( int index ) |
|
{ |
|
if ( index < 0 || index >= m_ReportType.Count() ) |
|
return "<<Invalid>>"; |
|
|
|
return m_BugStrings.String( m_ReportType[ index ] ); |
|
} |
|
|
|
char const *CBugReporter::GetRepositoryURL( void ) |
|
{ |
|
return m_BugRootDirectory; |
|
} |
|
|
|
// only valid after calling CBugReporter::StartNewBugReport() |
|
char const *CBugReporter::GetSubmissionURL( void ) |
|
{ |
|
return m_CurrentBugDirectory; |
|
} |
|
|
|
int CBugReporter::GetLevelCount(int area) |
|
{ |
|
CUtlSymbol area_sym = m_AreaMap[area-1]; |
|
int area_index = m_LevelMap.Find(area_sym); |
|
if (m_LevelMap.IsValidIndex(area_index)) |
|
{ |
|
CUtlVector<CUtlSymbol> *levels = m_LevelMap[area_index]; |
|
return levels->Count(); |
|
} |
|
return 0; |
|
} |
|
|
|
char const *CBugReporter::GetLevel(int area, int index ) |
|
{ |
|
CUtlSymbol area_sym = m_AreaMap[area-1]; |
|
int area_index = m_LevelMap.Find(area_sym); |
|
if (m_LevelMap.IsValidIndex(area_index)) |
|
{ |
|
CUtlVector<CUtlSymbol> *levels = m_LevelMap[area_index]; |
|
if (index >= 0 && index < levels->Count()) |
|
{ |
|
return m_BugStrings.String((*levels)[index]); |
|
} |
|
} |
|
|
|
return ""; |
|
} |
|
|
|
|
|
|
|
void CBugReporter::StartNewBugReport() |
|
{ |
|
if ( !m_pBug ) |
|
{ |
|
m_pBug = new CBug(); |
|
} |
|
else |
|
{ |
|
m_pBug->Clear(); |
|
} |
|
|
|
// Find the first available bug number by looking |
|
// for the next directory that doesn't exist. |
|
m_CurrentBugID = 0; |
|
struct tm t; |
|
|
|
do |
|
{ |
|
VCRHook_LocalTime( &t ); |
|
|
|
Q_snprintf(m_CurrentBugDirectory, sizeof(m_CurrentBugDirectory), "%s%c%04i%02i%02i-%02i%02i%02i-%s", |
|
m_BugRootDirectory, |
|
CORRECT_PATH_SEPARATOR, |
|
t.tm_year + 1900, t.tm_mon+1, t.tm_mday, |
|
t.tm_hour, t.tm_min, t.tm_sec, |
|
m_BugStrings.String(m_UserName)); |
|
if (_access(m_CurrentBugDirectory, 0) != 0) |
|
break; |
|
|
|
// sleep for a second or two then try again |
|
ThreadSleep(RandomInt(1000,2000)); |
|
} while ( 1 ); |
|
_mkdir(m_CurrentBugDirectory); |
|
} |
|
|
|
void CBugReporter::CancelNewBugReport() |
|
{ |
|
if ( !m_pBug ) |
|
return; |
|
|
|
m_pBug->Clear(); |
|
m_CurrentBugID = 0; |
|
} |
|
|
|
static void OutputField( CUtlBuffer &outbuf, char const *pFieldName, char const *pFieldValue ) |
|
{ |
|
if ( pFieldValue && pFieldValue[0] ) |
|
{ |
|
char const *pTmpString = V_AddBackSlashesToSpecialChars( pFieldValue ); |
|
outbuf.Printf( "%s=\"%s\"\n", pFieldName, pTmpString ); |
|
delete[] pTmpString; |
|
} |
|
} |
|
|
|
bool CBugReporter::CommitBugReport( int& bugSubmissionId ) |
|
{ |
|
bugSubmissionId = m_CurrentBugID; |
|
|
|
if ( !m_pBug ) |
|
return false; |
|
|
|
// Now create the bug descriptor file, and dump all the text keys in it |
|
CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER); |
|
|
|
OutputField( buf, "Title", m_pBug->title ); |
|
OutputField( buf, "Owner", m_pBug->owner ); |
|
OutputField( buf, "Submitter", m_pBug->submitter ); |
|
OutputField( buf, "Severity", m_pBug->severity ); |
|
// OutputField( buf, "Type", m_pBug->reporttype ); |
|
// OutputField( buf, "Priority", m_pBug->priority ); |
|
OutputField( buf, "Area", m_pBug->area ); |
|
OutputField( buf, "Level", m_pBug->mapnumber ); |
|
OutputField( buf, "Description", m_pBug->desc ); |
|
|
|
//OutputField( buf, "Level", m_pBug->level ); |
|
OutputField( buf, "Build", m_pBug->build ); |
|
OutputField( buf, "Position", m_pBug->position ); |
|
OutputField( buf, "Orientation", m_pBug->orientation ); |
|
|
|
OutputField( buf, "Screenshot", m_pBug->screenshot_unc ); |
|
OutputField( buf, "Savegame", m_pBug->savegame_unc ); |
|
OutputField( buf, "Bsp", m_pBug->bsp_unc ); |
|
OutputField( buf, "vmf", m_pBug->vmf_unc ); |
|
|
|
// if ( m_pBug->includedfiles.Count() > 0 ) |
|
// { |
|
// int c = m_pBug->includedfiles.Count(); |
|
// for ( int i = 0 ; i < c; ++i ) |
|
// { |
|
// buf.Printf( "include: %s\n", m_pBug->includedfiles[ i ].name ); |
|
// } |
|
// } |
|
OutputField( buf, "DriverInfo", m_pBug->driverinfo ); |
|
|
|
OutputField( buf, "Misc", m_pBug->misc ); |
|
|
|
|
|
// Write it out to the file |
|
// Need to use native calls to bypass steam filesystem |
|
char szBugFileName[1024]; |
|
Q_snprintf(szBugFileName, sizeof(szBugFileName), "%s%cbug.txt", m_CurrentBugDirectory, CORRECT_PATH_SEPARATOR ); |
|
FILE *fp = fopen(szBugFileName, "wb"); |
|
if (!fp) |
|
return false; |
|
|
|
fprintf(fp, "%s", (char *)buf.Base()); |
|
fclose(fp); |
|
|
|
// Clear the bug |
|
m_pBug->Clear(); |
|
|
|
return true; |
|
} |
|
|
|
void CBugReporter::SetTitle( char const *title ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->title, title, sizeof( m_pBug->title ) ); |
|
} |
|
|
|
void CBugReporter::SetDescription( char const *description ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->desc, description, sizeof( m_pBug->desc ) ); |
|
} |
|
|
|
void CBugReporter::SetSubmitter( char const *username /* = 0 */) |
|
{ |
|
if ( !username ) |
|
{ |
|
username = GetUserName(); |
|
} |
|
|
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->submitter, username, sizeof( m_pBug->submitter ) ); |
|
} |
|
|
|
void CBugReporter::SetOwner( char const *username ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->owner, username, sizeof( m_pBug->owner ) ); |
|
} |
|
|
|
void CBugReporter::SetSeverity( char const *severity ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->severity, severity, sizeof( m_pBug->severity ) ); |
|
} |
|
|
|
void CBugReporter::SetPriority( char const *priority ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->priority, priority, sizeof( m_pBug->priority ) ); |
|
} |
|
|
|
void CBugReporter::SetArea( char const *area ) |
|
{ |
|
Assert( m_pBug ); |
|
char const *game = GetAreaMapForArea(area); |
|
Q_strncpy( m_pBug->area, game, sizeof( m_pBug->area ) ); |
|
} |
|
|
|
void CBugReporter::SetMapNumber( char const *mapnumber ) |
|
{ |
|
Assert( m_pBug); |
|
Q_strncpy( m_pBug->mapnumber, mapnumber, sizeof( m_pBug->mapnumber ) ); |
|
} |
|
|
|
void CBugReporter::SetReportType( char const *reporttype ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->reporttype, reporttype, sizeof( m_pBug->reporttype ) ); |
|
} |
|
|
|
void CBugReporter::SetLevel( char const *levelnamne ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->level, levelnamne, sizeof( m_pBug->level ) ); |
|
} |
|
|
|
void CBugReporter::SetDriverInfo( char const *info ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->driverinfo, info, sizeof( m_pBug->driverinfo ) ); |
|
} |
|
|
|
void CBugReporter::SetMiscInfo( char const *info ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->misc, info, sizeof( m_pBug->misc ) ); |
|
} |
|
|
|
void CBugReporter::SetPosition( char const *position ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->position, position, sizeof( m_pBug->position ) ); |
|
} |
|
|
|
void CBugReporter::SetOrientation( char const *pitch_yaw_roll ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->orientation, pitch_yaw_roll, sizeof( m_pBug->orientation ) ); |
|
} |
|
|
|
void CBugReporter::SetBuildNumber( char const *build_num ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->build, build_num, sizeof( m_pBug->build ) ); |
|
} |
|
|
|
void CBugReporter::SetScreenShot( char const *screenshot_unc_address ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->screenshot_unc, screenshot_unc_address, sizeof( m_pBug->screenshot_unc ) ); |
|
} |
|
|
|
void CBugReporter::SetSaveGame( char const *savegame_unc_address ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->savegame_unc, savegame_unc_address, sizeof( m_pBug->savegame_unc ) ); |
|
} |
|
|
|
void CBugReporter::SetBSPName( char const *bsp_unc_address ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->bsp_unc, bsp_unc_address, sizeof( m_pBug->bsp_unc ) ); |
|
} |
|
|
|
void CBugReporter::SetVMFName( char const *vmf_unc_address ) |
|
{ |
|
Assert( m_pBug ); |
|
Q_strncpy( m_pBug->vmf_unc, vmf_unc_address, sizeof( m_pBug->vmf_unc ) ); |
|
} |
|
|
|
void CBugReporter::AddIncludedFile( char const *filename ) |
|
{ |
|
CBug::incfile includedfile; |
|
Q_strncpy( includedfile.name, filename, sizeof( includedfile.name ) ); |
|
m_pBug->includedfiles.AddToTail( includedfile ); |
|
} |
|
|
|
void CBugReporter::ResetIncludedFiles() |
|
{ |
|
m_pBug->includedfiles.Purge(); |
|
} |
|
|
|
bool CBugReporter::PopulateChoiceList( char const *listname, CUtlVector< CUtlSymbol >& list ) |
|
{ |
|
// Read choice lists from text file |
|
KeyValues *pKV = m_OptionsFile->FindKey( listname ); |
|
pKV = pKV->GetFirstSubKey(); |
|
while ( pKV ) |
|
{ |
|
CUtlSymbol sym = m_BugStrings.AddString( pKV->GetName() ); |
|
list.AddToTail( sym ); |
|
|
|
pKV = pKV->GetNextKey(); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool CBugReporter::SymbolLessThan(const CUtlSymbol &sym1, const CUtlSymbol &sym2) |
|
{ |
|
const char *string1 = m_BugStrings.String(sym1); |
|
const char *string2 = m_BugStrings.String(sym2); |
|
|
|
return Q_stricmp(string1, string2) < 0; |
|
} |
|
|
|
// owner, not required <<Unassigned>> |
|
// area <<None>> |
|
|
|
bool CBugReporter::PopulateLists() |
|
{ |
|
CUtlSymbol none = m_BugStrings.AddString( "<<None>>" ); |
|
m_Area.AddToTail( none ); |
|
|
|
PopulateChoiceList( "Severity", m_Severity ); |
|
|
|
// Get developer names from text file |
|
KeyValues *pKV = m_OptionsFile->FindKey( "Names" ); |
|
pKV = pKV->GetFirstSubKey(); |
|
while ( pKV ) |
|
{ |
|
// Fill in lookup table |
|
CUtlSymbol display_name_sym = m_BugStrings.AddString( pKV->GetName() ); |
|
CUtlSymbol user_name_sym = m_BugStrings.AddString( pKV->GetString() ); |
|
m_SortedDisplayNames.AddToTail( display_name_sym ); |
|
m_SortedUserNames.AddToTail( user_name_sym ); |
|
pKV = pKV->GetNextKey(); |
|
} |
|
|
|
pKV = m_OptionsFile->FindKey( "Area" ); |
|
pKV = pKV->GetFirstSubKey(); |
|
while(pKV) |
|
{ |
|
char const *area = pKV->GetName(); |
|
char const *game = pKV->GetString(); |
|
char areamap[256]; |
|
Q_snprintf(areamap, sizeof(areamap), "@%s", game); |
|
CUtlSymbol area_sym = m_BugStrings.AddString(area); |
|
CUtlSymbol area_map_sym = m_BugStrings.AddString(areamap); |
|
m_Area.AddToTail( area_sym ); |
|
m_AreaMap.AddToTail( area_map_sym ); |
|
pKV = pKV->GetNextKey(); |
|
} |
|
|
|
pKV = m_OptionsFile->FindKey( "Level" ); |
|
pKV = pKV->GetFirstSubKey(); |
|
while(pKV) |
|
{ |
|
char const *level = pKV->GetName(); |
|
char const *area = pKV->GetString(); |
|
char areamap[256]; |
|
Q_snprintf(areamap, sizeof(areamap), "@%s", area); |
|
|
|
CUtlSymbol level_sym = m_BugStrings.AddString(level); |
|
CUtlSymbol area_sym = m_BugStrings.Find(areamap); |
|
if (!area_sym.IsValid()) |
|
{ |
|
area_sym = m_BugStrings.AddString(areamap); |
|
} |
|
|
|
unsigned index = m_LevelMap.Find(area_sym); |
|
CUtlVector<CUtlSymbol> *levels = 0; |
|
|
|
if (m_LevelMap.IsValidIndex(index)) |
|
{ |
|
levels = m_LevelMap[index]; |
|
} |
|
else |
|
{ |
|
levels = new CUtlVector<CUtlSymbol>; |
|
Assert(levels); |
|
m_LevelMap.Insert(area_sym, levels); |
|
} |
|
|
|
if (level) |
|
{ |
|
levels->AddToTail(level_sym); |
|
} |
|
|
|
pKV = pKV->GetNextKey(); |
|
} |
|
|
|
|
|
|
|
return true; |
|
} |
|
|
|
EXPOSE_SINGLE_INTERFACE( CBugReporter, IBugReporter, INTERFACEVERSION_BUGREPORTER );
|
|
|