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

Generated on Mon Aug 30 19:14:02 2010 for Vidalia by  doxygen 1.5.9