diff --git a/code/nel/CMakeLists.txt b/code/nel/CMakeLists.txt index 53bf071e3..16a8166fe 100644 --- a/code/nel/CMakeLists.txt +++ b/code/nel/CMakeLists.txt @@ -83,4 +83,3 @@ IF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN) ENDIF(WITH_NEL_TOOLS) ADD_SUBDIRECTORY(tools) ENDIF(WITH_NEL_TOOLS OR WITH_NEL_MAXPLUGIN) - diff --git a/code/nel/include/nel/misc/debug.h b/code/nel/include/nel/misc/debug.h index 690d340a3..8d2483e4e 100644 --- a/code/nel/include/nel/misc/debug.h +++ b/code/nel/include/nel/misc/debug.h @@ -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) -#if defined (NL_OS_WINDOWS) -#define NLMISC_BREAKPOINT __debugbreak(); +#if defined(NL_OS_WINDOWS) +#define NLMISC_BREAKPOINT __debugbreak() +#elif defined(NL_OS_UNIX) && defined(NL_COMP_GCC) +#define NLMISC_BREAKPOINT __builtin_trap() #else #define NLMISC_BREAKPOINT abort() #endif diff --git a/code/nel/include/nel/misc/report.h b/code/nel/include/nel/misc/report.h index 11745b6e3..c492f4aa2 100644 --- a/code/nel/include/nel/misc/report.h +++ b/code/nel/include/nel/misc/report.h @@ -21,9 +21,11 @@ namespace NLMISC { +enum TReportResult { ReportDebug, ReportIgnore, ReportQuit, ReportError }; + /** 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 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 @@ -32,14 +34,15 @@ namespace NLMISC { * * \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 }; - -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 = ""); +/// Set the Url of the web service used to post crash reports to +void setReportPostUrl(const std::string &postUrl); +/// DEPRECATED /** call this in the main of your appli to enable email: setReportEmailFunction (sendEmail); */ -void setReportEmailFunction (void *emailFunction); +void setReportEmailFunction(void *emailFunction); } // NLMISC diff --git a/code/nel/src/misc/debug.cpp b/code/nel/src/misc/debug.cpp index 2a9c5282a..9fbce530b 100644 --- a/code/nel/src/misc/debug.cpp +++ b/code/nel/src/misc/debug.cpp @@ -78,7 +78,8 @@ using namespace std; #define LOG_IN_FILE NEL_LOG_IN_FILE // 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 #define new DEBUG_NEW @@ -1191,10 +1192,10 @@ void createDebug (const char *logPath, bool logInFile, bool eraseLastLog) #ifdef NL_OS_WINDOWS if (TrapCrashInDebugger || !IsDebuggerPresent ()) +#endif { DefaultMsgBoxDisplayer = new CMsgBoxDisplayer ("DEFAULT_MBD"); } -#endif #if LOG_IN_FILE if (logInFile) diff --git a/code/nel/src/misc/displayer.cpp b/code/nel/src/misc/displayer.cpp index 4b9231663..3a095f640 100644 --- a/code/nel/src/misc/displayer.cpp +++ b/code/nel/src/misc/displayer.cpp @@ -520,7 +520,7 @@ void CFileDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *mes // in release "" void CMsgBoxDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *message) { -#ifdef NL_OS_WINDOWS +//#ifdef NL_OS_WINDOWS bool needSpace = false; // stringstream ss; @@ -711,7 +711,7 @@ void CMsgBoxDisplayer::doDisplay ( const CLog::TDisplayInfo& args, const char *m } */ } -#endif +//#endif } diff --git a/code/nel/src/misc/report.cpp b/code/nel/src/misc/report.cpp index 20b2b1c11..7323716e3 100644 --- a/code/nel/src/misc/report.cpp +++ b/code/nel/src/misc/report.cpp @@ -16,6 +16,8 @@ #include "stdmisc.h" +#include + #include "nel/misc/common.h" #include "nel/misc/ucstring.h" @@ -42,83 +44,126 @@ using namespace std; namespace NLMISC { -#ifdef NL_OS_WINDOWS -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) +void setReportEmailFunction(void *emailFunction) { - EmailFunction = (TEmailFunction)emailFunction; - -#ifdef NL_OS_WINDOWS - if (sendReport) - EnableWindow(sendReport, FALSE); -#endif + // DEPRECATED + // no-op } -#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 report () +void setReportPostUrl(const std::string &postUrl) { + 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 -// Windows specific version +// Windows specific version for DEV builds, first shows a dialog box for debugging -static string Body; -static string Subject; -static string AttachedFile; +static HWND sendReport=NULL; +#define DELETE_OBJECT(a) if((a)!=NULL) { DeleteObject (a); a = NULL; } -static HWND checkIgnore=NULL; -static HWND debug=NULL; -static HWND ignore=NULL; -static HWND quit=NULL; -static HWND dialog=NULL; +static HWND checkIgnore = NULL; +static HWND debug = NULL; +static HWND ignore = NULL; +static HWND quit = NULL; +static HWND dialog = NULL; static bool NeedExit; static TReportResult Result; static bool IgnoreNextTime; -static bool CanSendMailReport= false; +static bool CanSendMailReport = false; static bool DebugDefaultBehavior, QuitDefaultBehavior; -static void sendEmail() +static void maybeSendReport() { if (CanSendMailReport && SendMessage(sendReport, BM_GETCHECK, 0, 0) != BST_CHECKED) { - bool res = EmailFunction ("", "", "", Subject, Body, AttachedFile, false); - if (res) - { - // EnableWindow(sendReport, FALSE); - // MessageBox (dialog, "The email was successfully sent", "email", MB_OK); + doSendReport(); #ifndef NL_NO_DEBUG_FILES - CFile::createEmptyFile(getLogDirectory() + "report_sent"); + CFile::createEmptyFile(getLogDirectory() + "report_sent"); #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 { #ifndef NL_NO_DEBUG_FILES CFile::createEmptyFile(getLogDirectory() + "report_refused"); #endif - } +- } } 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) { - sendEmail(); + maybeSendReport(); NeedExit = true; Result = ReportDebug; if (DebugDefaultBehavior) @@ -143,13 +188,13 @@ static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM } else if ((HWND) lParam == ignore) { - sendEmail(); + maybeSendReport(); NeedExit = true; Result = ReportIgnore; } else if ((HWND) lParam == quit) { - sendEmail(); + maybeSendReport(); NeedExit = true; Result = ReportQuit; @@ -168,43 +213,26 @@ static LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM 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) { if (wParam == 27) { // ESC -> ignore - sendEmail(); + maybeSendReport(); NeedExit = true; 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 static bool AlreadyRegister = false; - if(!AlreadyRegister) + if (!AlreadyRegister) { WNDCLASSW wc; memset (&wc,0,sizeof(wc)); @@ -222,8 +250,8 @@ TReportResult report (const std::string &title, const std::string &header, const 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 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 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 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); @@ -241,10 +266,10 @@ TReportResult report (const std::string &title, const std::string &header, const // set the edit text limit to lot of :) SendMessage (edit, EM_LIMITTEXT, ~0U, 0); - Body = addSlashR (body); + ReportBody = addSlashR(body); // 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) { @@ -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 - //CanSendMailReport = sendReportButton && EmailFunction != NULL && EmailFunction("", "", "", "", "", true); - CanSendMailReport = sendReportButton && EmailFunction != NULL; + CanSendMailReport = sendReportButton && !ReportPostUrl.empty(); 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)."; diff --git a/code/nel/tools/misc/CMakeLists.txt b/code/nel/tools/misc/CMakeLists.txt index 5386cbbc6..c9bbcd058 100644 --- a/code/nel/tools/misc/CMakeLists.txt +++ b/code/nel/tools/misc/CMakeLists.txt @@ -3,6 +3,7 @@ SUBDIRS(bnp_make disp_sheet_id extract_filename lock make_sheet_id xml_packer) IF(WITH_QT) ADD_SUBDIRECTORY(words_dic_qt) ADD_SUBDIRECTORY(message_box_qt) + ADD_SUBDIRECTORY(crash_report) ENDIF(WITH_QT) IF(WIN32) diff --git a/code/nel/tools/misc/crash_report/CMakeLists.txt b/code/nel/tools/misc/crash_report/CMakeLists.txt new file mode 100644 index 000000000..0e2d2a9bc --- /dev/null +++ b/code/nel/tools/misc/crash_report/CMakeLists.txt @@ -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}) + diff --git a/code/nel/tools/misc/crash_report/crash_report.cpp b/code/nel/tools/misc/crash_report/crash_report.cpp new file mode 100644 index 000000000..e083de126 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report.cpp @@ -0,0 +1,92 @@ +// Nel MMORPG framework - Error Reporter +// +// Copyright (C) 2015 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// 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 . + + +#include "crash_report_widget.h" +#include +#include + +#include +#include +#include + +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(); +} \ No newline at end of file diff --git a/code/nel/tools/misc/crash_report/crash_report_data.h b/code/nel/tools/misc/crash_report/crash_report_data.h new file mode 100644 index 000000000..5884e7eb4 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report_data.h @@ -0,0 +1,33 @@ +// Ryzom Core MMORPG framework - Error Reporter +// +// Copyright (C) 2015 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// 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 . + + +#ifndef RCERROR_DATA +#define RCERROR_DATA + +#include + + +struct SCrashReportData +{ + QString description; + QString report; + QString email; +}; + +#endif diff --git a/code/nel/tools/misc/crash_report/crash_report_socket.cpp b/code/nel/tools/misc/crash_report/crash_report_socket.cpp new file mode 100644 index 000000000..5f8720e05 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report_socket.cpp @@ -0,0 +1,65 @@ +// Nel MMORPG framework - Error Reporter +// +// Copyright (C) 2015 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// 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 . + +#include "crash_report_socket.h" +#include +#include +#include +#include + +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(); +} + diff --git a/code/nel/tools/misc/crash_report/crash_report_socket.h b/code/nel/tools/misc/crash_report/crash_report_socket.h new file mode 100644 index 000000000..32ccc5da0 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report_socket.h @@ -0,0 +1,55 @@ +// Nel MMORPG framework - Error Reporter +// +// Copyright (C) 2015 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// 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 . + + +#ifndef RCERROR_SOCKET +#define RCERROR_SOCKET + +#include +#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 + diff --git a/code/nel/tools/misc/crash_report/crash_report_widget.cpp b/code/nel/tools/misc/crash_report/crash_report_widget.cpp new file mode 100644 index 000000000..968978f94 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report_widget.cpp @@ -0,0 +1,171 @@ +// Nel MMORPG framework - Error Reporter +// +// Copyright (C) 2015 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// 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 . + + +#include "crash_report_widget.h" +#include "crash_report_socket.h" +#include "crash_report_data.h" +#include +#include +#include +#include +#include + +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 > > ¶ms ) +{ + 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(); +} + diff --git a/code/nel/tools/misc/crash_report/crash_report_widget.h b/code/nel/tools/misc/crash_report/crash_report_widget.h new file mode 100644 index 000000000..61b56e340 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report_widget.h @@ -0,0 +1,60 @@ +// Nel MMORPG framework - Error Reporter +// +// Copyright (C) 2015 Laszlo Kis-Adam +// Copyright (C) 2010 Ryzom Core +// +// 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 . + + +#ifndef RCERROR_WIDGET +#define RCERROR_WIDGET + + +#include "ui_crash_report_widget.h" +#include +#include + +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 > > ¶ms ); + +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 + diff --git a/code/nel/tools/misc/crash_report/crash_report_widget.ui b/code/nel/tools/misc/crash_report/crash_report_widget.ui new file mode 100644 index 000000000..589810578 --- /dev/null +++ b/code/nel/tools/misc/crash_report/crash_report_widget.ui @@ -0,0 +1,82 @@ + + + CrashReportWidget + + + Qt::ApplicationModal + + + + 0 + 0 + 400 + 407 + + + + NeL Error Report + + + + + + What were you doing when the crash occured? + + + + + + + + + + Contents of the report ( automatically generated ) + + + + + + + true + + + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + Email me if you have further questions, or updates on this issue + + + + + + + false + + + Enter your email address here + + + + + + + Send + + + + + + + Cancel + + + + + + + + diff --git a/code/ryzom/client/src/connection.cpp b/code/ryzom/client/src/connection.cpp index 92ecff0ac..3f3a3d809 100644 --- a/code/ryzom/client/src/connection.cpp +++ b/code/ryzom/client/src/connection.cpp @@ -103,7 +103,6 @@ extern uint32 Version; // Client Version. extern UDriver *Driver; extern UTextContext *TextContext; extern bool game_exit; -extern CMsgBoxDisplayer MsgBoxError; extern CSoundManager *SoundMngr; diff --git a/code/ryzom/client/src/init.cpp b/code/ryzom/client/src/init.cpp index 33bec822f..5484141a2 100644 --- a/code/ryzom/client/src/init.cpp +++ b/code/ryzom/client/src/init.cpp @@ -142,7 +142,6 @@ using namespace std; // Ligo primitive class CLigoConfig LigoConfig; -CMsgBoxDisplayer MsgBoxError; CClientChatManager ChatMngr; bool LastScreenSaverEnabled = false; diff --git a/code/web/public_php/crash_report/config.inc.php b/code/web/public_php/crash_report/config.inc.php new file mode 100644 index 000000000..fe4b3e928 --- /dev/null +++ b/code/web/public_php/crash_report/config.inc.php @@ -0,0 +1,30 @@ + +// +// 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 . + +class BugReportConfig +{ + static public $dbhost = "localhost"; + static public $dbport = "3306"; + static public $dbdb = "bugs"; + static public $dbuser = "bugs"; + static public $dbpw = "bugs"; +} + +?> diff --git a/code/web/public_php/crash_report/log.inc.php b/code/web/public_php/crash_report/log.inc.php new file mode 100644 index 000000000..71deee24f --- /dev/null +++ b/code/web/public_php/crash_report/log.inc.php @@ -0,0 +1,45 @@ + +// +// 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 . + +/// 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" ); + } +} + +?> diff --git a/code/web/public_php/crash_report/submit.php b/code/web/public_php/crash_report/submit.php new file mode 100644 index 000000000..d20214d11 --- /dev/null +++ b/code/web/public_php/crash_report/submit.php @@ -0,0 +1,112 @@ + +// +// 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 . + +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(); + +?>