diff options
Diffstat (limited to 'drkonqi/toplevel.cpp')
-rw-r--r-- | drkonqi/toplevel.cpp | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/drkonqi/toplevel.cpp b/drkonqi/toplevel.cpp new file mode 100644 index 000000000..a35388dd5 --- /dev/null +++ b/drkonqi/toplevel.cpp @@ -0,0 +1,520 @@ +/***************************************************************** + * drkonqi - The KDE Crash Handler + * + * Copyright (C) 2000-2003 Hans Petter Bieker <[email protected]> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************/ + +#include <tqstring.h> +#include <tqlabel.h> +#include <tqhbox.h> + +#include <tdelocale.h> +#include <tdeglobal.h> +#include <kstandarddirs.h> +#include <kbugreport.h> +#include <tdefiledialog.h> +#include <tdemessagebox.h> +#include <kprocess.h> +#include <tdeapplication.h> +#include <dcopclient.h> +#include <tdetempfile.h> + +#include "netwm.h" + +#include "backtrace.h" +#include "drbugreport.h" +#include "bugdescription.h" +#include "debugger.h" +#include "krashconf.h" +#include "sha1.h" +#include "toplevel.h" +#include "toplevel.moc" + +Toplevel :: Toplevel(KrashConfig *krashconf, TQWidget *parent, const char *name) + : KDialogBase( Tabbed, + krashconf->programName(), + User3 | User2 | User1 | Close, + Close, + parent, + name, + true, // modal + false, // no separator + i18n("&Bug report"), + i18n("&Debugger"), + i18n("&Report Crash") + ), + m_krashconf(krashconf), m_bugreport(0), m_bugdescription(0) +{ + TQHBox *page = addHBoxPage(i18n("&General")); + page->setSpacing(20); + + // picture of konqi + TQLabel *lab = new TQLabel(page); + lab->setFrameStyle(TQFrame::Panel | TQFrame::Sunken); + TQPixmap pix(locate("appdata", TQString::fromLatin1("pics/konqi.png"))); + lab->setPixmap(pix); + lab->setFixedSize( lab->sizeHint() ); + + TQLabel * info = new TQLabel(generateText(), page); + info->setMinimumSize(info->sizeHint()); + + if (m_krashconf->showBacktrace()) + { + page = addHBoxPage(i18n("&Backtrace")); + new KrashDebugger(m_krashconf, page); + } + + showButton( User1, m_krashconf->showBugReport() ); + showButton( User2, m_krashconf->showDebugger() ); + showButton( User3, true ); + + connect(this, TQT_SIGNAL(closeClicked()), TQT_SLOT(accept())); + connect(m_krashconf, TQT_SIGNAL(newDebuggingApplication(const TQString&)), TQT_SLOT(slotNewDebuggingApp(const TQString&))); + + if ( !m_krashconf->safeMode() && kapp->dcopClient()->attach() ) + kapp->dcopClient()->registerAs( kapp->name() ); +} + +Toplevel :: ~Toplevel() +{ +} + +TQString Toplevel :: generateText() const +{ + TQString str; + + if (!m_krashconf->errorDescriptionText().isEmpty()) + str += i18n("<p><b>Short description</b></p><p>%1</p>") + .arg(m_krashconf->errorDescriptionText()); + + if (!m_krashconf->signalText().isEmpty()) + str += i18n("<p><b>What is this?</b></p><p>%1</p>") + .arg(m_krashconf->signalText()); + + if (!m_krashconf->whatToDoText().isEmpty()) + str += i18n("<p><b>What can I do?</b></p><p>%1</p>") + .arg(m_krashconf->whatToDoText()); + + // check if the string is still empty. if so, display a default. + if (str.isEmpty()) + str = i18n("<p><b>Application crashed</b></p>" + "<p>The program %appname crashed.</p>"); + + // scan the string for %appname etc + m_krashconf->expandString(str, false); + + return str; +} + +// starting bug report +void Toplevel :: slotUser1() +{ + if (m_bugreport) + return; + + int i = KMessageBox::No; + if ( m_krashconf->pid() != 0 ) + i = KMessageBox::warningYesNoCancel + (0, + i18n("<p>Do you want to generate a " + "backtrace? This will help the " + "developers to figure out what went " + "wrong.</p>\n" + "<p>Unfortunately this will take some " + "time on slow machines.</p>" + "<p><b>Note: A backtrace is not a " + "substitute for a proper description " + "of the bug and information on how to " + "reproduce it. It is not possible " + "to fix the bug without a proper " + "description.</b></p>"), + i18n("Include Backtrace"),i18n("Generate"),i18n("Do Not Generate")); + + if (i == KMessageBox::Cancel) return; + + m_bugreport = new DrKBugReport(0, true, m_krashconf->aboutData()); + + if (i == KMessageBox::Yes) { + TQApplication::setOverrideCursor ( tqwaitCursor ); + + // generate the backtrace + BackTrace *backtrace = new BackTrace(m_krashconf, TQT_TQOBJECT(this)); + connect(backtrace, TQT_SIGNAL(someError()), TQT_SLOT(slotBacktraceSomeError())); + connect(backtrace, TQT_SIGNAL(done(const TQString &)), TQT_SLOT(slotBacktraceDone(const TQString &))); + + backtrace->start(); + + return; + } + + int result = m_bugreport->exec(); + delete m_bugreport; + m_bugreport = 0; + if (result == KDialogBase::Accepted) + close(); +} + +void Toplevel :: slotUser2() +{ + TQString str = m_krashconf->debugger(); + m_krashconf->expandString(str, true); + + TDEProcess proc; + proc.setUseShell(true); + proc << str; + proc.start(TDEProcess::DontCare); +} + +void Toplevel :: slotNewDebuggingApp(const TQString& launchName) +{ + setButtonText( User3, launchName ); + showButton( User3, true ); +} + +void Toplevel :: slotUser3() +{ + enableButton(User3, false); + TQApplication::setOverrideCursor ( tqwaitCursor ); + + // generate the backtrace + BackTrace *backtrace = new BackTrace(m_krashconf, TQT_TQOBJECT(this)); + connect(backtrace, TQT_SIGNAL(someError()), TQT_SLOT(slotSendReportBacktraceSomeError())); + connect(backtrace, TQT_SIGNAL(done(const TQString &)), TQT_SLOT(slotSendReportBacktraceDone(const TQString &))); + + backtrace->start(); + + return; +} + +void Toplevel :: slotBacktraceDone(const TQString &str) +{ + // Do not translate.. This will be included in the _MAIL_. + TQString buf = TQString::fromLatin1 + ("\n\n\nHere is a backtrace generated by DrKonqi:\n") + str; + + m_bugreport->setText(buf); + + TQApplication::restoreOverrideCursor(); + + m_bugreport->exec(); + delete m_bugreport; + m_bugreport = 0; +} + +void Toplevel :: slotBacktraceSomeError() +{ + TQApplication::restoreOverrideCursor(); + + KMessageBox::sorry(0, i18n("It was not possible to generate a backtrace."), + i18n("Backtrace Not Possible")); + + m_bugreport->exec(); + delete m_bugreport; + m_bugreport = 0; +} + +void Toplevel::slotSendReportBacktraceSomeError() +{ + TQApplication::restoreOverrideCursor(); + + KMessageBox::sorry(0, i18n("It was not possible to generate a backtrace."), i18n("Backtrace Not Possible")); + + delete m_bugdescription; + m_bugdescription = 0; + + enableButton(User3, true); +} + +void Toplevel::slotSendReportBacktraceDone(const TQString &str) +{ + int i = KMessageBox::No; + if ( m_krashconf->pid() != 0 ) { + i = KMessageBox::warningYesNoCancel + (0, + i18n("<p>Do you want to include a " + "description of what you were doing " + "when this application crashed? This " + "would help the " + "developers to figure out what went " + "wrong.</p>\n"), + i18n("Include Description"),i18n("Add Description"),i18n("Just Report the Crash")); + } + + if (i == KMessageBox::Cancel) { + TQApplication::restoreOverrideCursor(); + enableButton(User3, true); + + return; + } + + m_bugdescription = new BugDescription(0, true, m_krashconf->aboutData()); + + if (i == KMessageBox::Yes) { + // Get description + // Also get Email address if desired + // Possibly reduce hash difficulty if Email address provided? + // BugDescription + if (m_bugdescription->exec() == TQDialog::Rejected) { + delete m_bugdescription; + m_bugdescription = 0; + + return; + } + } + + // Get automatic system information + TQString autoSystemInformation; + KBugReport* kbugreport = new KBugReport(0, true, m_krashconf->aboutData()); + autoSystemInformation += "Application: "; + autoSystemInformation += m_krashconf->appName(); + autoSystemInformation += "\n"; + autoSystemInformation += "Signal: "; + autoSystemInformation += TQString("%1").arg(m_krashconf->signalNumber()); + autoSystemInformation += "\n"; + autoSystemInformation += "Compiler: "; + autoSystemInformation += kbugreport->compilerVersion(); + autoSystemInformation += "\n"; + autoSystemInformation += "Kernel: "; + autoSystemInformation += kbugreport->operatingSystem(); + autoSystemInformation += "\n"; + autoSystemInformation += "TDE Version: "; + autoSystemInformation += kbugreport->tdeVersion(); + autoSystemInformation += "\n"; + autoSystemInformation += "Timestamp: "; + autoSystemInformation += TQString("%1").arg(TQDateTime::currentDateTime().toTime_t()); + autoSystemInformation += "\n"; + delete kbugreport; + kbugreport = 0; + + // Generate automatic crash description + TQString autoCrashDescription = m_krashconf->errorDescriptionText(); + m_krashconf->expandString(autoCrashDescription, false); + + // Generate full crash report + TQString backtraceSubmission = str; + backtraceSubmission.append("\n==== (tdebugreport) automatic crash description ====\n"); + backtraceSubmission.append(TQString("%1\n").arg(autoCrashDescription)); + backtraceSubmission.append("\n==== (tdebugreport) automatic system description ====\n"); + backtraceSubmission.append(TQString("%1\n").arg(autoSystemInformation)); + if (m_bugdescription->emailAddress().contains("@") && m_bugdescription->emailAddress().contains(".")) { + backtraceSubmission.append("\n==== (tdebugreport) reporting Email address ====\n"); + backtraceSubmission.append(TQString("%1\n").arg(m_bugdescription->emailAddress())); + } + if (m_bugdescription->crashDescription() != "") { + backtraceSubmission.append("\n==== (tdebugreport) user-generated crash description ====\n"); + backtraceSubmission.append(TQString("%1\n").arg(m_bugdescription->crashDescription())); + } + + // Calculate proof-of-work hash + SHA1 sha; + TQByteArray hash(sha.size() / 8); + hash.fill(255); + + backtraceSubmission.append("\n==== (tdebugreport) proof of work ====\n"); + int proofOfWorkPos = backtraceSubmission.length(); + backtraceSubmission.append(TQUuid::createUuid().toString()); + m_backtraceSubmissionData = TQCString(backtraceSubmission.ascii()); + + while ((hash[0] != 0) || ((hash[1] & 0xfc) != 0)) { // First 14 bits of the SHA1 hash must be zero + TQCString proofOfWork(TQUuid::createUuid().toString().ascii()); + memcpy(m_backtraceSubmissionData.data() + proofOfWorkPos, proofOfWork.data(), proofOfWork.size()); + sha.reset(); + sha.process(m_backtraceSubmissionData.data(), m_backtraceSubmissionData.size()-1); + memcpy(hash.data(), sha.hash(), hash.size()); + } + + TQApplication::restoreOverrideCursor(); + + i = KMessageBox::Yes; + while (i == KMessageBox::Yes) { + i = KMessageBox::warningYesNoCancel + (0, + i18n("<p>The crash report is ready. Do you want to send it now?</p>\n"), + i18n("Ready to Send"),i18n("View Report"),i18n("Send Report")); + + if (i == KMessageBox::Cancel) { + delete m_bugdescription; + m_bugdescription = 0; + enableButton(User3, true); + + return; + } + + if (i == KMessageBox::Yes) { + BugDescription fullReport(0, true, NULL); + fullReport.fullReportViewMode(true); + fullReport.setText(TQString(m_backtraceSubmissionData.data())); + fullReport.showMaximized(); + fullReport.exec(); + } + } + + postCrashDataToServer(m_backtraceSubmissionData); + + delete m_bugdescription; + m_bugdescription = 0; +} + +int Toplevel::postCrashDataToServer(TQCString data) { + m_serverResponse = ""; + TQCString formDataBoundary = "-----------------------------------DrKonqiCrashReporterBoundary"; + + TQCString postData; + postData += "--"; + postData += formDataBoundary; + postData += "\r\n"; + postData += "Content-Disposition: form-data; name=\"crashreport\"; filename=\"crashreport.txt\"\r\n"; + postData += "Content-Type: application/octet-stream\r\n"; + postData += (TQString("Content-Length: %1\r\n").arg(data.count())).ascii(); + postData += "Content-Transfer-Encoding: binary\r\n\r\n"; + postData += data; + postData += "\r\n"; + postData += "--"; + postData += formDataBoundary; + postData += "--\r\n"; + + KURL url("https://crashreport.trinitydesktop.org/"); +// TDEIO::TransferJob* job = TDEIO::http_post(url, postData, false); + TDEIO::TransferJob* job = TDEIO::http_post(url, postData, true); + job->addMetaData("content-type", TQString("Content-Type: multipart/form-data; boundary=%1").arg(formDataBoundary)); + job->addMetaData("referrer", "http://drkonqi-client.crashreport.trinitydesktop.org"); + connect(job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), TQT_SLOT(postCrashDataToServerData(TDEIO::Job *, const TQByteArray &))); + connect(job, TQT_SIGNAL(result(TDEIO::Job *)), TQT_SLOT(postCrashDataToServerResult(TDEIO::Job *))); +// connect(job, TQT_SIGNAL(totalSize(TDEIO::Job *, TDEIO::filesize_t )), +// TQT_SLOT(totalSize(TDEIO::Job *, TDEIO::filesize_t))); +// connect(job, TQT_SIGNAL(mimetype(TDEIO::Job *, const TQString &)), +// TQT_SLOT(mimetype(TDEIO::Job *, const TQString &))); + connect(job, TQT_SIGNAL(redirection(TDEIO::Job *, const KURL&)), TQT_SLOT(postCrashDataToServerDataRedirection(TDEIO::Job *, const KURL&))); + + return 0; +} + +void Toplevel::postCrashDataToServerData(TDEIO::Job *, const TQByteArray &ba) +{ + uint offset = 0; + if (m_serverResponse.count() > 0) { + offset = m_serverResponse.count() - 1; + } + uint size = ba.count(); + + m_serverResponse.resize(offset + size + 1); + memcpy(m_serverResponse.data() + offset, ba.data(), size); + *(m_serverResponse.data() + offset + size) = 0; +} + +void Toplevel::postCrashDataToServerResult(TDEIO::Job *job) +{ + int err = job->error(); + if (err == 0) { + TQString responseString(m_serverResponse); + if (responseString.startsWith("ACK\n")) { + responseString = responseString.mid(4); + KMessageBox::information + (0, + i18n("<p>Your crash report has been uploaded!</p></p>You may reference it if desired by its unique ID:<br>%1</p>").arg(responseString), + i18n("Report uploaded")); + close(); + } + else { + responseString = responseString.mid(4); +// KMessageBox::error +// (0, +// i18n("<p>Your crash report failed to upload!</p><p>Please check your network settings and try again.</p><p>The server responded:<br>%1</p>").arg(responseString), +// i18n("Upload failure")); + + int i = KMessageBox::warningYesNoCancel + (0, + i18n("<p>Your crash report failed to upload!</p><p>Please check your network settings and try again.</p><p>The server responded:<br>%1</p>").arg(responseString), + i18n("Upload failure"),i18n("Save Report"),i18n("Retry Upload")); + + if (i == KMessageBox::No) { + postCrashDataToServer(m_backtraceSubmissionData); + } + else if (i == KMessageBox::Yes) { + saveOfflineCrashReport(m_backtraceSubmissionData); + } + else { + enableButton(User3, true); + } + } + } + else { + int i = KMessageBox::warningYesNoCancel + (0, + i18n("<p>Your crash report failed to upload!</p><p>Please check your network settings and try again.</p>"), + i18n("Upload failure"),i18n("Save Report"),i18n("Retry Upload")); + + if (i == KMessageBox::No) { + postCrashDataToServer(m_backtraceSubmissionData); + } + else if (i == KMessageBox::Yes) { + saveOfflineCrashReport(m_backtraceSubmissionData); + } + else { + enableButton(User3, true); + } + } +} + +int Toplevel::saveOfflineCrashReport(TQCString data) +{ + TQString defname = m_krashconf->execName() + TQString::fromLatin1( ".tdecrash" ); + if( defname.contains( '/' )) + defname = defname.mid( defname.findRev( '/' ) + 1 ); + TQString filename = KFileDialog::getSaveFileName(defname, TQString::null, this, i18n("Select Filename")); + if (filename.isEmpty()) { + enableButton(User3, true); + return 1; + } + else { + TQFile f(filename); + + if (f.exists()) { + if (KMessageBox::Cancel == + KMessageBox::warningContinueCancel( 0, + i18n( "A file named \"%1\" already exists. " + "Are you sure you want to overwrite it?" ).arg( filename ), + i18n( "Overwrite File?" ), + i18n( "&Overwrite" ) )) + return 2; + } + + if (f.open(IO_WriteOnly)) { + f.writeBlock(data.data(), data.count()-1); + f.close(); + enableButton(User3, true); + return 0; + } + else { + KMessageBox::sorry(this, i18n("Cannot open file %1 for writing").arg(filename)); + enableButton(User3, true); + return 3; + } + } +} + +void Toplevel::postCrashDataToServerDataRedirection(TDEIO::Job * /*job*/, const KURL& url) +{ + // +}
\ No newline at end of file |