Vidalia 0.2.12

crashreporter/main.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file main.cpp
00013 ** \brief Application that is run after Vidalia crashes and asks the
00014 ** user if they would like to submit the crash report.
00015 */
00016 
00017 #include "CrashReportDialog.h"
00018 
00019 #include <QApplication>
00020 #include <QFileInfo>
00021 #include <QMessageBox>
00022 #include <QTextStream>
00023 #include <QTextCodec>
00024 
00025 
00026 /** Open the minidump file  given by <b>fileName</b> and read its entire
00027  * contents into a QByteArray. Returns the contents of the minidump file
00028  * on success. If an error occurs, this returns a default-constructed
00029  * QByteArray and sets <b>errorMessage</b> to a string describing the error
00030  * ecountered.
00031  */
00032 QByteArray
00033 read_minidump_file(const QString &fileName, QString &errorMessage)
00034 {
00035   QByteArray md;
00036   QFile mdFile(fileName);
00037 
00038   if (! mdFile.open(QIODevice::ReadOnly)) {
00039     errorMessage = mdFile.errorString();
00040     return QByteArray();
00041   }
00042   while (! mdFile.atEnd()) {
00043     md.append(mdFile.readAll());
00044     if (mdFile.error() != QFile::NoError) {
00045       errorMessage = mdFile.errorString();
00046       return QByteArray();
00047     }
00048   }
00049   mdFile.close();
00050   return md;
00051 }
00052 
00053 /** Read the crash dump annotations file given by <b>fileName</b> and parse
00054  * each line into a Key=Value pair. Returns a QHash containing the keys
00055  * mapped to their values on success. If a file or parse error occurs, this
00056  * returns a default-constructed QHash and sets <b>errorMessage</b> to a
00057  * string describing the error encountered.
00058  */
00059 QHash<QString,QString>
00060 read_annotations_file(const QString &fileName, QString &errorMessage)
00061 {
00062   QHash<QString, QString> annotations;
00063 
00064   /* Open the annotations file for reading text */
00065   QFile infile(fileName);
00066   if (! infile.open(QIODevice::ReadOnly | QIODevice::Text)) {
00067     errorMessage = infile.errorString();
00068     return QHash<QString,QString>();
00069   }
00070 
00071   /* The annotations file should be UTF-8 encoded */
00072   QTextStream reader(&infile);
00073   reader.setCodec(QTextCodec::codecForName("utf-8"));
00074   while (! reader.atEnd()) {
00075     QString line = reader.readLine().trimmed();
00076     if (line.isEmpty())
00077       continue;
00078 
00079     int idx = line.indexOf("=");
00080     if (idx > 0 && idx < line.length()-1) {
00081       QString key = line.mid(0, idx).trimmed();
00082       QString val = line.mid(idx + 1).trimmed();
00083       annotations.insert(key, val); 
00084     }
00085   }
00086   return annotations;
00087 }
00088 
00089 int
00090 main(int argc, char *argv[])
00091 {
00092   QApplication app(argc, argv);
00093   CrashReportDialog crashDialog;
00094   QFileInfo minidumpFile, extraInfoFile;
00095   QString minidumpFilePath, extraInfoFilePath, errorMessage;
00096   QHash<QString,QString> annotations;
00097   QByteArray minidump;
00098 
00099   if (argc < 2) {
00100     errorMessage = "No minidump file specified.";
00101     goto err;
00102   }
00103 
00104   /* Ensure that the specified minidump file exists and is readable */
00105   minidumpFile     = QFileInfo(argv[1]);
00106   minidumpFilePath = minidumpFile.absoluteFilePath();
00107   if (! minidumpFile.exists() || ! minidumpFile.size()) {
00108     errorMessage = QString("The specified minidump file does not exist: %1")
00109                                                       .arg(minidumpFilePath);
00110     goto err;
00111   }
00112   if (! minidumpFile.isReadable()) {
00113     errorMessage = QString("The specified minidump file is not readable: %1")
00114                                                        .arg(minidumpFilePath);
00115     goto err;
00116   }
00117 
00118   /* Ensure that the specified minidump has an associated extra crash
00119    * information file that exists and is readable. */
00120   extraInfoFile     = QFileInfo(minidumpFilePath + ".info");
00121   extraInfoFilePath = extraInfoFile.absoluteFilePath();
00122   if (! extraInfoFile.exists() || ! extraInfoFile.size()) {
00123     errorMessage = QString("The specified minidump does not have a "
00124                            "corresponding crash annotations file: %1")
00125                                                .arg(extraInfoFilePath);
00126     goto err;
00127   }
00128   if (! extraInfoFile.isReadable()) {
00129     errorMessage = QString("The specified crash information file is not "
00130                            "readable: %1").arg(extraInfoFilePath);
00131     goto err;
00132   }
00133 
00134   /* Read the minidump file's contents */
00135   minidump = read_minidump_file(minidumpFilePath, errorMessage);
00136   if (minidump.isNull()) {
00137     errorMessage = QString("Unable to read minidump file '%1': %2")
00138                                              .arg(minidumpFilePath)
00139                                              .arg(errorMessage);
00140     goto err;
00141   }
00142   /* Read and parse the crash annotations file */
00143   annotations = read_annotations_file(extraInfoFilePath, errorMessage);
00144   if (annotations.isEmpty()) {
00145     errorMessage = QString("Unable to read crash annotations file '%1': %2")
00146                                                      .arg(extraInfoFilePath)
00147                                                      .arg(errorMessage);
00148     goto err;
00149   }
00150 
00151   /* Display the crash reporting dialog */
00152   crashDialog.setMinidump(minidumpFile.baseName(), minidump);
00153   crashDialog.setCrashAnnotations(annotations);
00154   crashDialog.show();
00155   return app.exec();
00156 
00157 err:
00158   /* We encountered an error trying to load the minidump or extra crash
00159    * information file. So, display an error and then bail, since now there's
00160    * nothing for us to send. */
00161   QMessageBox dlg;
00162   dlg.setWindowIcon(QIcon(":/images/32x32/tools-report-bug.png"));
00163   dlg.setWindowTitle("Crash Reporter Error");
00164 
00165   dlg.setIconPixmap(QPixmap(":/images/64x64/tools-report-bug.png"));
00166   dlg.setStandardButtons(QMessageBox::Ok);
00167 
00168   dlg.setText("<b>Vidalia encountered an error and needed to close</b>");
00169   dlg.setInformativeText(
00170     "<p>Vidalia attempted to automatically create an error report to "
00171     "help diagnose the problem, but was unable to do so. Please report "
00172     "this problem, along with what you were doing before Vidalia crashed, "
00173     "to the developers at:</p><p>"
00174     "<a href=\"https://trac.vidalia-project.net/wiki/ReportingBugs\">"
00175     "https://trac.vidalia-project.net/wiki/ReportingBugs</a></p> "
00176     "<p>Click \"Show Details\" below for information about the problem "
00177     "encountered.");
00178 
00179   dlg.setDetailedText(errorMessage);
00180   return dlg.exec();
00181 }