Merge with feature-crashreport

This commit is contained in:
kaetemi 2015-02-24 11:41:05 +01:00
commit 5307229afa
20 changed files with 907 additions and 95 deletions

View file

@ -83,4 +83,3 @@ IF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN)
ENDIF(WITH_NEL_TOOLS) ENDIF(WITH_NEL_TOOLS)
ADD_SUBDIRECTORY(tools) ADD_SUBDIRECTORY(tools)
ENDIF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN) ENDIF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN)

View file

@ -350,8 +350,10 @@ void setCrashAlreadyReported(bool state);
*/ */
// removed because we always check assert (even in release mode) #if defined (NL_OS_WINDOWS) && defined (NL_DEBUG) // removed because we always check assert (even in release mode) #if defined (NL_OS_WINDOWS) && defined (NL_DEBUG)
#if defined (NL_OS_WINDOWS) #if defined(NL_OS_WINDOWS)
#define NLMISC_BREAKPOINT __debugbreak(); #define NLMISC_BREAKPOINT __debugbreak()
#elif defined(NL_OS_UNIX) && defined(NL_COMP_GCC)
#define NLMISC_BREAKPOINT __builtin_trap()
#else #else
#define NLMISC_BREAKPOINT abort() #define NLMISC_BREAKPOINT abort()
#endif #endif

View file

@ -21,9 +21,11 @@
namespace NLMISC { namespace NLMISC {
enum TReportResult { ReportDebug, ReportIgnore, ReportQuit, ReportError };
/** Display a custom message box. /** Display a custom message box.
* *
* \param title set the title of the report. If empty, it'll display "NeL report". * \param title set the title of the report. If empty, it'll display "NeL Crash Report" or the default title set by setReportWindowTitle.
* \param header message displayed before the edit text box. If empty, it displays the default message. * \param header message displayed before the edit text box. If empty, it displays the default message.
* \param body message displayed in the edit text box. This string will be sent by email. * \param body message displayed in the edit text box. This string will be sent by email.
* \param debugButton 0 for disabling it, 1 for enable with default behaviors (generate a breakpoint), 2 for enable with no behavior * \param debugButton 0 for disabling it, 1 for enable with default behaviors (generate a breakpoint), 2 for enable with no behavior
@ -32,14 +34,15 @@ namespace NLMISC {
* *
* \return the button clicked or error * \return the button clicked or error
*/ */
TReportResult report(const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const std::string &attachedFile = "");
enum TReportResult { ReportDebug, ReportIgnore, ReportQuit, ReportError }; /// Set the Url of the web service used to post crash reports to
void setReportPostUrl(const std::string &postUrl);
TReportResult report (const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const std::string &attachedFile = "");
/// DEPRECATED
/** call this in the main of your appli to enable email: setReportEmailFunction (sendEmail); /** call this in the main of your appli to enable email: setReportEmailFunction (sendEmail);
*/ */
void setReportEmailFunction (void *emailFunction); void setReportEmailFunction(void *emailFunction);
} // NLMISC } // NLMISC

View file

@ -78,7 +78,8 @@ using namespace std;
#define LOG_IN_FILE NEL_LOG_IN_FILE #define LOG_IN_FILE NEL_LOG_IN_FILE
// If true, debug system will trap crash even if the application is in debugger // If true, debug system will trap crash even if the application is in debugger
static const bool TrapCrashInDebugger = false; //static const bool TrapCrashInDebugger = false;
static const bool TrapCrashInDebugger = true;
#ifdef DEBUG_NEW #ifdef DEBUG_NEW
#define new DEBUG_NEW #define new DEBUG_NEW
@ -1191,10 +1192,10 @@ void createDebug (const char *logPath, bool logInFile, bool eraseLastLog)
#ifdef NL_OS_WINDOWS #ifdef NL_OS_WINDOWS
if (TrapCrashInDebugger || !IsDebuggerPresent ()) if (TrapCrashInDebugger || !IsDebuggerPresent ())
#endif
{ {
DefaultMsgBoxDisplayer = new CMsgBoxDisplayer ("DEFAULT_MBD"); DefaultMsgBoxDisplayer = new CMsgBoxDisplayer ("DEFAULT_MBD");
} }
#endif
#if LOG_IN_FILE #if LOG_IN_FILE
if (logInFile) if (logInFile)

View file

@ -520,7 +520,7 @@ void CFileDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *mes
// in release "<Msg>" // in release "<Msg>"
void CMsgBoxDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message) void CMsgBoxDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message)
{ {
#ifdef NL_OS_WINDOWS //#ifdef NL_OS_WINDOWS
bool needSpace = false; bool needSpace = false;
// stringstream ss; // stringstream ss;
@ -711,7 +711,7 @@ void CMsgBoxDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *m
} }
*/ } */ }
#endif //#endif
} }

View file

@ -16,6 +16,8 @@
#include "stdmisc.h" #include "stdmisc.h"
#include <stringstream>
#include "nel/misc/common.h" #include "nel/misc/common.h"
#include "nel/misc/ucstring.h" #include "nel/misc/ucstring.h"
@ -42,83 +44,126 @@ using namespace std;
namespace NLMISC namespace NLMISC
{ {
#ifdef NL_OS_WINDOWS void setReportEmailFunction(void *emailFunction)
static HWND sendReport=NULL;
#endif
//old doesn't work on visual c++ 7.1 due to default parameter typedef bool (*TEmailFunction) (const std::string &smtpServer, const std::string &from, const std::string &to, const std::string &subject, const std::string &body, const std::string &attachedFile = "", bool onlyCheck = false);
typedef bool (*TEmailFunction) (const std::string &smtpServer, const std::string &from, const std::string &to, const std::string &subject, const std::string &body, const std::string &attachedFile, bool onlyCheck);
#define DELETE_OBJECT(a) if((a)!=NULL) { DeleteObject (a); a = NULL; }
static TEmailFunction EmailFunction = NULL;
void setReportEmailFunction (void *emailFunction)
{ {
EmailFunction = (TEmailFunction)emailFunction; // DEPRECATED
// no-op
#ifdef NL_OS_WINDOWS
if (sendReport)
EnableWindow(sendReport, FALSE);
#endif
} }
#ifndef NL_OS_WINDOWS // Contents of crash report
static string ReportBody;
// Host url for crash report
static std::string ReportPostUrl = "";
// Title for the crash report window
static std::string ReportWindowTitle = "";
// GNU/Linux, do nothing void setReportPostUrl(const std::string &postUrl)
void report ()
{ {
ReportPostUrl = postUrl;
}
// Launch the crash report application
static void doSendReport()
{
std::string filename;
filename = /*getLogDirectory() + */ "report_"; // FIXME: Should use log directory
filename += NLMISC::toString( int( time( NULL ) ) );
filename += ".txt";
std::stringstream params;
params << "-log ";
params << filename; // FIXME: Escape the filepath with quotes
if (!ReportPostUrl.empty())
{
params << " -host ";
params << ReportPostUrl;
}
if (!ReportWindowTitle.empty())
{
params << " -title ";
params << ReportWindowTitle; // FIXME: Escape the title with quotes and test
}
std::ofstream f;
f.open( filename.c_str() );
if( !f.good() )
return;
f << ReportBody;
f.close();
#ifdef NL_OS_WINDOWS
NLMISC::launchProgram( "crash_report.exe", params.str() );
#else
NLMISC::launchProgram( "crash_report", params.str() );
#endif
// Added because NLSMIC::launcProgram needs time to launch
nlSleep( 2 * 1000 );
}
#if defined(FINAL_VERSION) || !defined(NL_OS_WINDOWS)
// For FINAL_VERSION, simply launch the crash report and exit the application
TReportResult report(const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const string &attachedFile)
{
ReportWindowTitle = title.empty() ? "Nel Crash Report" : title;
ReportBody = addSlashR(body);
doSendReport();
# if defined(FINAL_VERSION) // TODO: This behaviour is used in the old report code when Quitting the application is the default crash report behaviour. Needs testing.
# ifdef NL_OS_WINDOWS
# ifndef NL_COMP_MINGW
// disable the Windows popup telling that the application aborted and disable the dr watson report.
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
# endif
# endif
// quit without calling atexit or static object dtors.
abort();
# endif
return ReportQuit;
} }
#else #else
// Windows specific version // Windows specific version for DEV builds, first shows a dialog box for debugging
static string Body; static HWND sendReport=NULL;
static string Subject; #define DELETE_OBJECT(a) if((a)!=NULL) { DeleteObject (a); a = NULL; }
static string AttachedFile;
static HWND checkIgnore=NULL; static HWND checkIgnore = NULL;
static HWND debug=NULL; static HWND debug = NULL;
static HWND ignore=NULL; static HWND ignore = NULL;
static HWND quit=NULL; static HWND quit = NULL;
static HWND dialog=NULL; static HWND dialog = NULL;
static bool NeedExit; static bool NeedExit;
static TReportResult Result; static TReportResult Result;
static bool IgnoreNextTime; static bool IgnoreNextTime;
static bool CanSendMailReport= false; static bool CanSendMailReport = false;
static bool DebugDefaultBehavior, QuitDefaultBehavior; static bool DebugDefaultBehavior, QuitDefaultBehavior;
static void sendEmail() static void maybeSendReport()
{ {
if (CanSendMailReport && SendMessage(sendReport, BM_GETCHECK, 0, 0) != BST_CHECKED) if (CanSendMailReport && SendMessage(sendReport, BM_GETCHECK, 0, 0) != BST_CHECKED)
{ {
bool res = EmailFunction ("", "", "", Subject, Body, AttachedFile, false); doSendReport();
if (res)
{
// EnableWindow(sendReport, FALSE);
// MessageBox (dialog, "The email was successfully sent", "email", MB_OK);
#ifndef NL_NO_DEBUG_FILES #ifndef NL_NO_DEBUG_FILES
CFile::createEmptyFile(getLogDirectory() + "report_sent"); CFile::createEmptyFile(getLogDirectory() + "report_sent");
#endif #endif
}
else
{
#ifndef NL_NO_DEBUG_FILES
CFile::createEmptyFile(getLogDirectory() + "report_failed");
#endif
// MessageBox (dialog, "Failed to send the email", "email", MB_OK | MB_ICONERROR);
}
} }
else else
{ {
#ifndef NL_NO_DEBUG_FILES #ifndef NL_NO_DEBUG_FILES
CFile::createEmptyFile(getLogDirectory() + "report_refused"); CFile::createEmptyFile(getLogDirectory() + "report_refused");
#endif #endif
} - }
} }
static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
@ -133,7 +178,7 @@ static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM
} }
else if ((HWND) lParam == debug) else if ((HWND) lParam == debug)
{ {
sendEmail(); maybeSendReport();
NeedExit = true; NeedExit = true;
Result = ReportDebug; Result = ReportDebug;
if (DebugDefaultBehavior) if (DebugDefaultBehavior)
@ -143,13 +188,13 @@ static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM
} }
else if ((HWND) lParam == ignore) else if ((HWND) lParam == ignore)
{ {
sendEmail(); maybeSendReport();
NeedExit = true; NeedExit = true;
Result = ReportIgnore; Result = ReportIgnore;
} }
else if ((HWND) lParam == quit) else if ((HWND) lParam == quit)
{ {
sendEmail(); maybeSendReport();
NeedExit = true; NeedExit = true;
Result = ReportQuit; Result = ReportQuit;
@ -168,43 +213,26 @@ static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM
abort(); abort();
} }
} }
/*else if ((HWND) lParam == sendReport)
{
if (EmailFunction != NULL)
{
bool res = EmailFunction ("", "", "", Subject, Body, AttachedFile, false);
if (res)
{
EnableWindow(sendReport, FALSE);
MessageBox (dialog, "The email was successfully sent", "email", MB_OK);
CFile::createEmptyFile(getLogDirectory() + "report_sent");
}
else
{
MessageBox (dialog, "Failed to send the email", "email", MB_OK | MB_ICONERROR);
}
}
}*/
} }
else if (message == WM_CHAR) else if (message == WM_CHAR)
{ {
if (wParam == 27) if (wParam == 27)
{ {
// ESC -> ignore // ESC -> ignore
sendEmail(); maybeSendReport();
NeedExit = true; NeedExit = true;
Result = ReportIgnore; Result = ReportIgnore;
} }
} }
return DefWindowProc (hWnd, message, wParam, lParam); return DefWindowProc(hWnd, message, wParam, lParam);
} }
TReportResult report (const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const string &attachedFile) TReportResult report(const std::string &title, const std::string &header, const std::string &subject, const std::string &body, bool enableCheckIgnore, uint debugButton, bool ignoreButton, sint quitButton, bool sendReportButton, bool &ignoreNextTime, const string &attachedFile)
{ {
// register the window // register the window
static bool AlreadyRegister = false; static bool AlreadyRegister = false;
if(!AlreadyRegister) if (!AlreadyRegister)
{ {
WNDCLASSW wc; WNDCLASSW wc;
memset (&wc,0,sizeof(wc)); memset (&wc,0,sizeof(wc));
@ -222,8 +250,8 @@ TReportResult report (const std::string &title, const std::string &header, const
AlreadyRegister = true; AlreadyRegister = true;
} }
ucstring formatedTitle = title.empty() ? ucstring("NeL report") : ucstring(title); ReportWindowTitle = title.empty() ? "Nel Crash Report" : title;
ucstring formatedTitle = ucstring::makeFromUtf8(ReportWindowTitle);
// create the window // create the window
dialog = CreateWindowW (L"NLReportWindow", (LPCWSTR)formatedTitle.c_str(), WS_DLGFRAME | WS_CAPTION /*| WS_THICKFRAME*/, CW_USEDEFAULT, CW_USEDEFAULT, 456, 400, NULL, NULL, GetModuleHandle(NULL), NULL); dialog = CreateWindowW (L"NLReportWindow", (LPCWSTR)formatedTitle.c_str(), WS_DLGFRAME | WS_CAPTION /*| WS_THICKFRAME*/, CW_USEDEFAULT, CW_USEDEFAULT, 456, 400, NULL, NULL, GetModuleHandle(NULL), NULL);
@ -231,9 +259,6 @@ TReportResult report (const std::string &title, const std::string &header, const
// create the font // create the font
HFONT font = CreateFont (-12, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial"); HFONT font = CreateFont (-12, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial");
Subject = subject;
AttachedFile = attachedFile;
// create the edit control // create the edit control
HWND edit = CreateWindowW (L"EDIT", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_READONLY | ES_LEFT | ES_MULTILINE, 7, 70, 429, 212, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL); HWND edit = CreateWindowW (L"EDIT", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | ES_READONLY | ES_LEFT | ES_MULTILINE, 7, 70, 429, 212, dialog, (HMENU) NULL, (HINSTANCE) GetWindowLongPtr(dialog, GWLP_HINSTANCE), NULL);
SendMessage (edit, WM_SETFONT, (WPARAM) font, TRUE); SendMessage (edit, WM_SETFONT, (WPARAM) font, TRUE);
@ -241,10 +266,10 @@ TReportResult report (const std::string &title, const std::string &header, const
// set the edit text limit to lot of :) // set the edit text limit to lot of :)
SendMessage (edit, EM_LIMITTEXT, ~0U, 0); SendMessage (edit, EM_LIMITTEXT, ~0U, 0);
Body = addSlashR (body); ReportBody = addSlashR(body);
// set the message in the edit text // set the message in the edit text
SendMessage (edit, WM_SETTEXT, (WPARAM)0, (LPARAM)Body.c_str()); SendMessage (edit, WM_SETTEXT, (WPARAM)0, (LPARAM)ReportBody.c_str());
if (enableCheckIgnore) if (enableCheckIgnore)
{ {
@ -294,8 +319,7 @@ TReportResult report (const std::string &title, const std::string &header, const
} }
// ace don't do that because it s slow to try to send a mail // ace don't do that because it s slow to try to send a mail
//CanSendMailReport = sendReportButton && EmailFunction != NULL && EmailFunction("", "", "", "", "", true); CanSendMailReport = sendReportButton && !ReportPostUrl.empty();
CanSendMailReport = sendReportButton && EmailFunction != NULL;
if (CanSendMailReport) if (CanSendMailReport)
formatedHeader += " Send report will only email the contents of the box below. Please, send it to help us (it could take few minutes to send the email, be patient)."; formatedHeader += " Send report will only email the contents of the box below. Please, send it to help us (it could take few minutes to send the email, be patient).";

View file

@ -3,6 +3,7 @@ SUBDIRS(bnp_make disp_sheet_id extract_filename lock make_sheet_id xml_packer)
IF(WITH_QT) IF(WITH_QT)
ADD_SUBDIRECTORY(words_dic_qt) ADD_SUBDIRECTORY(words_dic_qt)
ADD_SUBDIRECTORY(message_box_qt) ADD_SUBDIRECTORY(message_box_qt)
ADD_SUBDIRECTORY(crash_report)
ENDIF(WITH_QT) ENDIF(WITH_QT)
IF(WIN32) IF(WIN32)

View file

@ -0,0 +1,39 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SRC_DIR} ${QT_INCLUDES})
FILE(GLOB CRASHREPORT_SRC *.cpp)
FILE(GLOB CRASHREPORT_HDR *h)
SET(CRASHREPORT_MOC_HDR
crash_report_socket.h
crash_report_widget.h
)
SET(CRASHREPORT_UI
crash_report_widget.ui
)
SET(QT_USE_QTGUI TRUE)
SET(QT_USE_QTNETWORK TRUE)
SET(QT_USE_QTMAIN TRUE)
SET(QT_USE_QTOPENGL FALSE)
SET(QT_USE_QTXML FALSE)
INCLUDE(${QT_USE_FILE})
ADD_DEFINITIONS(${QT_DEFINITIONS})
QT4_WRAP_CPP(CRASHREPORT_MOC_SRC ${CRASHREPORT_MOC_HDR})
QT4_WRAP_UI(CRASHREPORT_UI_HDR ${CRASHREPORT_UI})
SOURCE_GROUP(QtResources FILES ${CRASHREPORT_UI})
SOURCE_GROUP(QtGeneratedUiHdr FILES ${CRASHREPORT_UI_HDR})
SOURCE_GROUP(QtGeneratedMocQrcSrc FILES ${CRASHREPORT_MOC_SRC})
SOURCE_GROUP("source files" FILES ${CRASHREPORT_SRC})
SOURCE_GROUP("header files" FILES ${CRASHREPORT_HDR})
ADD_EXECUTABLE(crash_report WIN32 MACOSX_BUNDLE ${CRASHREPORT_SRC} ${CRASHREPORT_MOC_HDR} ${CRASHREPORT_MOC_SRC} ${CRASHREPORT_UI_HDR})
TARGET_LINK_LIBRARIES(crash_report ${QT_LIBRARIES} ${QT_QTMAIN_LIBRARY})
NL_DEFAULT_PROPS(crash_report "NeL, Tools, Misc: Crash Report")
NL_ADD_RUNTIME_FLAGS(crash_report)
INSTALL(TARGETS crash_report RUNTIME DESTINATION ${NL_BIN_PREFIX})

View file

@ -0,0 +1,92 @@
// Nel MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "crash_report_widget.h"
#include <QApplication>
#include <QMessageBox>
#include <stack>
#include <vector>
#include <string>
class CCmdLineParser
{
public:
static void parse( int argc, char **argv, std::vector< std::pair< std::string, std::string > > &v )
{
std::stack< std::string > stack;
std::string key;
std::string value;
for( int i = argc - 1 ; i >= 0; i-- )
{
stack.push( std::string( argv[ i ] ) );
}
while( !stack.empty() )
{
key = stack.top();
stack.pop();
// If not a real parameter ( they start with '-' ), discard.
if( key[ 0 ] != '-' )
continue;
// Remove the '-'
key = key.substr( 1 );
// No more parameters
if( stack.empty() )
{
v.push_back( std::make_pair( key, "" ) );
break;
}
value = stack.top();
// If next parameter is a key, process it in the next iteration
if( value[ 0 ] == '-' )
{
v.push_back( std::make_pair( key, "" ) );
continue;
}
// Otherwise store the pair
else
{
v.push_back( std::make_pair( key, value ) );
stack.pop();
}
}
}
};
int main( int argc, char **argv )
{
QApplication app( argc, argv );
std::vector< std::pair< std::string, std::string > > params;
CCmdLineParser::parse( argc, argv, params );
CCrashReportWidget w;
w.setup( params );
w.show();
return app.exec();
}

View file

@ -0,0 +1,33 @@
// Ryzom Core MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RCERROR_DATA
#define RCERROR_DATA
#include <QString>
struct SCrashReportData
{
QString description;
QString report;
QString email;
};
#endif

View file

@ -0,0 +1,65 @@
// Nel MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "crash_report_socket.h"
#include <QNetworkAccessManager>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
class CCrashReportSocketPvt
{
public:
QNetworkAccessManager mgr;
};
CCrashReportSocket::CCrashReportSocket( QObject *parent ) :
QObject( parent )
{
m_pvt = new CCrashReportSocketPvt();
connect( &m_pvt->mgr, SIGNAL( finished( QNetworkReply* ) ), this, SLOT( onFinished( QNetworkReply* ) ) );
}
CCrashReportSocket::~CCrashReportSocket()
{
delete m_pvt;
}
void CCrashReportSocket::sendReport( const SCrashReportData &data )
{
QUrl params;
params.addQueryItem( "report", data.report );
params.addQueryItem( "descr", data.description );
params.addQueryItem( "email", data.email );
QUrl url( m_url );
QNetworkRequest request( url );
request.setRawHeader( "Connection", "close" );
m_pvt->mgr.post( request, params.encodedQuery() );
}
void CCrashReportSocket::onFinished( QNetworkReply *reply )
{
if( reply->error() != QNetworkReply::NoError )
Q_EMIT reportFailed();
else
Q_EMIT reportSent();
}

View file

@ -0,0 +1,55 @@
// Nel MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RCERROR_SOCKET
#define RCERROR_SOCKET
#include <QObject>
#include "crash_report_data.h"
class CCrashReportSocketPvt;
class QNetworkReply;
class CCrashReportSocket : public QObject
{
Q_OBJECT
public:
CCrashReportSocket( QObject *parent );
~CCrashReportSocket();
void setURL( const char *URL ){ m_url = URL; }
QString url() const{ return m_url; }
void sendReport( const SCrashReportData &data );
Q_SIGNALS:
void reportSent();
void reportFailed();
private Q_SLOTS:
void onFinished( QNetworkReply *reply );
private:
CCrashReportSocketPvt *m_pvt;
QString m_url;
};
#endif

View file

@ -0,0 +1,171 @@
// Nel MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "crash_report_widget.h"
#include "crash_report_socket.h"
#include "crash_report_data.h"
#include <QTimer>
#include <QTextStream>
#include <QFile>
#include <QMessageBox>
#include <QFile>
CCrashReportWidget::CCrashReportWidget( QWidget *parent ) :
QWidget( parent )
{
m_ui.setupUi( this );
m_socket = new CCrashReportSocket( this );
QTimer::singleShot( 1, this, SLOT( onLoad() ) );
connect( m_ui.sendButton, SIGNAL( clicked( bool ) ), this, SLOT( onSendClicked() ) );
connect( m_ui.canceButton, SIGNAL( clicked( bool ) ), this, SLOT( onCancelClicked() ) );
connect( m_ui.emailCB, SIGNAL( stateChanged( int ) ), this, SLOT( onCBClicked() ) );
connect( m_socket, SIGNAL( reportSent() ), this, SLOT( onReportSent() ) );
connect( m_socket, SIGNAL( reportFailed() ), this, SLOT( onReportFailed() ) );
}
CCrashReportWidget::~CCrashReportWidget()
{
m_socket = NULL;
}
void CCrashReportWidget::setup( const std::vector< std::pair< std::string, std::string > > &params )
{
for( int i = 0; i < params.size(); i++ )
{
const std::pair< std::string, std::string > &p = params[ i ];
const std::string &k = p.first;
const std::string &v = p.second;
if( k == "log" )
{
m_fileName = v.c_str();
}
else
if( k == "host" )
{
m_socket->setURL( v.c_str() );
}
else
if( k == "title" )
{
setWindowTitle( v.c_str() );
}
}
}
void CCrashReportWidget::onLoad()
{
if( !checkSettings() )
{
close();
return;
}
QFile f( m_fileName );
bool b = f.open( QFile::ReadOnly | QFile::Text );
if( !b )
{
QMessageBox::information( this,
tr( "No log file found" ),
tr( "There was no log file found, therefore nothing to report. Exiting..." ) );
close();
return;
}
QTextStream ss( &f );
m_ui.reportEdit->setPlainText( ss.readAll() );
f.close();
}
void CCrashReportWidget::onSendClicked()
{
m_ui.sendButton->setEnabled( false );
QApplication::setOverrideCursor( Qt::WaitCursor );
SCrashReportData data;
data.description = m_ui.descriptionEdit->toPlainText();
data.report = m_ui.reportEdit->toPlainText();
data.email = m_ui.emailEdit->text();
m_socket->sendReport( data );
}
void CCrashReportWidget::onCancelClicked()
{
removeAndQuit();
}
void CCrashReportWidget::onCBClicked()
{
m_ui.emailEdit->setEnabled( m_ui.emailCB->isChecked() );
}
void CCrashReportWidget::onReportSent()
{
QApplication::setOverrideCursor( Qt::ArrowCursor );
QMessageBox::information( this,
tr( "Report sent" ),
tr( "The report has been sent." ) );
removeAndQuit();
}
void CCrashReportWidget::onReportFailed()
{
QApplication::setOverrideCursor( Qt::ArrowCursor );
QMessageBox::information( this,
tr( "Report failed" ),
tr( "Failed to send the report..." ) );
removeAndQuit();
}
bool CCrashReportWidget::checkSettings()
{
if( m_fileName.isEmpty() )
{
QMessageBox::information( this,
tr( "No log file specified." ),
tr( "No log file specified. Exiting..." ) );
return false;
}
if( m_socket->url().isEmpty() )
{
QMessageBox::information( this,
tr( "No host specified." ),
tr( "No host specified. Exiting..." ) );
return false;
}
return true;
}
void CCrashReportWidget::removeAndQuit()
{
QFile::remove( m_fileName );
close();
}

View file

@ -0,0 +1,60 @@
// Nel MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef RCERROR_WIDGET
#define RCERROR_WIDGET
#include "ui_crash_report_widget.h"
#include <vector>
#include <string>
class CCrashReportSocket;
class CCrashReportWidget : public QWidget
{
Q_OBJECT
public:
CCrashReportWidget( QWidget *parent = NULL );
~CCrashReportWidget();
void setFileName( const char *fn ){ m_fileName = fn; }
void setup( const std::vector< std::pair< std::string, std::string > > &params );
private Q_SLOTS:
void onLoad();
void onSendClicked();
void onCancelClicked();
void onCBClicked();
void onReportSent();
void onReportFailed();
private:
bool checkSettings();
void removeAndQuit();
Ui::CrashReportWidget m_ui;
QString m_fileName;
CCrashReportSocket *m_socket;
};
#endif

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CrashReportWidget</class>
<widget class="QWidget" name="CrashReportWidget">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle">
<string>NeL Error Report</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>What were you doing when the crash occured?</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPlainTextEdit" name="descriptionEdit"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Contents of the report ( automatically generated )</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPlainTextEdit" name="reportEdit">
<property name="enabled">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="emailCB">
<property name="text">
<string>Email me if you have further questions, or updates on this issue</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QLineEdit" name="emailEdit">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Enter your email address here</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="sendButton">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QPushButton" name="canceButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -103,7 +103,6 @@ extern uint32 Version; // Client Version.
extern UDriver *Driver; extern UDriver *Driver;
extern UTextContext *TextContext; extern UTextContext *TextContext;
extern bool game_exit; extern bool game_exit;
extern CMsgBoxDisplayer MsgBoxError;
extern CSoundManager *SoundMngr; extern CSoundManager *SoundMngr;

View file

@ -142,7 +142,6 @@ using namespace std;
// Ligo primitive class // Ligo primitive class
CLigoConfig LigoConfig; CLigoConfig LigoConfig;
CMsgBoxDisplayer MsgBoxError;
CClientChatManager ChatMngr; CClientChatManager ChatMngr;
bool LastScreenSaverEnabled = false; bool LastScreenSaverEnabled = false;

View file

@ -0,0 +1,30 @@
<?php
// Ryzom Core MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
class BugReportConfig
{
static public $dbhost = "localhost";
static public $dbport = "3306";
static public $dbdb = "bugs";
static public $dbuser = "bugs";
static public $dbpw = "bugs";
}
?>

View file

@ -0,0 +1,45 @@
<?php
// Ryzom Core MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/// Simple file logger class
class Logger
{
private $lf = NULL;
function __construct()
{
$this->lf = fopen( 'log.txt', 'a' );
if( $this->lf === FALSE )
exit( 1 );
}
function __destruct()
{
fclose( $this->lf );
}
public function log( $msg )
{
$date = date( "[M d, Y H:i:s] " );
fwrite( $this->lf, $date . $msg . "\n" );
}
}
?>

View file

@ -0,0 +1,112 @@
<?php
// Ryzom Core MMORPG framework - Error Reporter
//
// Copyright (C) 2015 Laszlo Kis-Adam
// Copyright (C) 2010 Ryzom Core <http://ryzomcore.org/>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
require_once( 'config.inc.php' );
require_once( 'log.inc.php' );
/// Example web application that takes bug reports from the bug reporter Qt app
class BugReportGatherApp
{
private $db = NULL;
private $logger = NULL;
function __construct()
{
$this->logger = new Logger();
}
private function logPOSTVars()
{
$report = "";
$descr = "";
$email = "";
if( isset( $_POST[ 'report' ] ) )
$report = $_POST[ 'report' ];
if( isset( $_POST[ 'descr' ] ) )
$descr = $_POST[ 'descr' ];
if( isset( $_POST[ 'email' ] ) )
$email = $_POST[ 'email' ];
$this->logger->log( 'report: ' . "\n" . $report );
$this->logger->log( 'description: ' . "\n" . $descr );
$this->logger->log( 'email: ' . "\n" . $email );
}
private function buildQuery()
{
$report = "";
$descr = "";
$email = "";
if( isset( $_POST[ 'report' ] ) )
$report = $_POST[ 'report' ];
if( isset( $_POST[ 'descr' ] ) )
$descr = $_POST[ 'descr' ];
if( isset( $_POST[ 'email' ] ) )
$email = $_POST[ 'email' ];
$report = $this->db->real_escape_string( $report );
$descr = $this->db->real_escape_string( $descr );
$email = $this->db->real_escape_string( $email );
$q = "INSERT INTO `bugs` (`report`,`description`,`email`) VALUES (";
$q .= "'$report',";
$q .= "'$descr',";
$q .= "'$email')";
return $q;
}
public function exec()
{
//$this->logPOSTVars();
$this->db = new mysqli( BugReportConfig::$dbhost, BugReportConfig::$dbuser, BugReportConfig::$dbpw, BugReportConfig::$dbdb, BugReportConfig::$dbport );
if( mysqli_connect_error() )
{
$this->logger->log( "Connection error :(" );
$this->logger->log( mysqli_connect_error() );
return;
}
$q = $this->buildQuery();
$result = $this->db->query( $q );
if( $result !== TRUE )
{
$this->logger->log( "Query failed :(" );
$this->logger->log( 'Query: ' . $q );
$this->logPOSTVars();
}
$this->db->close();
}
}
$app = new BugReportGatherApp();
$app->exec();
?>