Vidalia  0.2.17
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.torproject.org/projects/vidalia.html. No part of Vidalia, 
00007 **  including this file, may be copied, modified, propagated, or distributed 
00008 **  except according to the 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 /** Read the crash dump annotations file given by <b>fileName</b> and parse
00026  * each line into a Key=Value pair. Returns a QHash containing the keys
00027  * mapped to their values on success. If a file or parse error occurs, this
00028  * returns a default-constructed QHash and sets <b>errorMessage</b> to a
00029  * string describing the error encountered.
00030  */
00031 QHash<QString,QString>
00032 read_annotations_file(const QString &fileName, QString &errorMessage)
00033 {
00034   QHash<QString, QString> annotations;
00035 
00036   /* Open the annotations file for reading text */
00037   QFile infile(fileName);
00038   if (! infile.open(QIODevice::ReadOnly | QIODevice::Text)) {
00039     errorMessage = infile.errorString();
00040     return QHash<QString,QString>();
00041   }
00042 
00043   /* The annotations file should be UTF-8 encoded */
00044   QTextStream reader(&infile);
00045   reader.setCodec(QTextCodec::codecForName("utf-8"));
00046   while (! reader.atEnd()) {
00047     QString line = reader.readLine().trimmed();
00048     if (line.isEmpty())
00049       continue;
00050 
00051     int idx = line.indexOf("=");
00052     if (idx > 0 && idx < line.length()-1) {
00053       QString key = line.mid(0, idx).trimmed();
00054       QString val = line.mid(idx + 1).trimmed();
00055       annotations.insert(key, val); 
00056     }
00057   }
00058   return annotations;
00059 }
00060 
00061 int
00062 main(int argc, char *argv[])
00063 {
00064   QApplication app(argc, argv);
00065   CrashReportDialog crashDialog;
00066   QFileInfo minidumpFile, extraInfoFile;
00067   QString minidumpFilePath, extraInfoFilePath, errorMessage;
00068   QHash<QString,QString> annotations;
00069 
00070   if (argc < 2) {
00071     errorMessage = "No minidump file specified.";
00072     goto err;
00073   }
00074 
00075   /* Ensure that the specified minidump file exists and is readable */
00076   minidumpFile     = QFileInfo(argv[1]);
00077   minidumpFilePath = minidumpFile.absoluteFilePath();
00078   if (! minidumpFile.exists() || ! minidumpFile.size()) {
00079     errorMessage = QString("The specified minidump file does not exist: %1")
00080                                                       .arg(minidumpFilePath);
00081     goto err;
00082   }
00083   if (! minidumpFile.isReadable()) {
00084     errorMessage = QString("The specified minidump file is not readable: %1")
00085                                                        .arg(minidumpFilePath);
00086     goto err;
00087   }
00088 
00089   /* Ensure that the specified minidump has an associated extra crash
00090    * information file that exists and is readable. */
00091   extraInfoFile     = QFileInfo(minidumpFilePath + ".info");
00092   extraInfoFilePath = extraInfoFile.absoluteFilePath();
00093   if (! extraInfoFile.exists() || ! extraInfoFile.size()) {
00094     errorMessage = QString("The specified minidump does not have a "
00095                            "corresponding crash annotations file: %1")
00096                                                .arg(extraInfoFilePath);
00097     goto err;
00098   }
00099   if (! extraInfoFile.isReadable()) {
00100     errorMessage = QString("The specified crash information file is not "
00101                            "readable: %1").arg(extraInfoFilePath);
00102     goto err;
00103   }
00104 
00105   /* Read and parse the crash annotations file */
00106   annotations = read_annotations_file(extraInfoFilePath, errorMessage);
00107   if (annotations.isEmpty()) {
00108     errorMessage = QString("Unable to read crash annotations file '%1': %2")
00109                                                      .arg(extraInfoFilePath)
00110                                                      .arg(errorMessage);
00111     goto err;
00112   }
00113 
00114   /* Display the crash reporting dialog */
00115   crashDialog.setCrashAnnotations(annotations);
00116   crashDialog.setMinidumpFiles(minidumpFilePath, extraInfoFilePath);
00117   crashDialog.show();
00118   return app.exec();
00119 
00120 err:
00121   /* We encountered an error trying to load the minidump or extra crash
00122    * information file. So, display an error and then bail, since now there's
00123    * nothing for us to send. */
00124   QMessageBox dlg;
00125   dlg.setWindowIcon(QIcon(":/images/32x32/tools-report-bug.png"));
00126   dlg.setWindowTitle("Crash Reporter Error");
00127 
00128   dlg.setIconPixmap(QPixmap(":/images/64x64/tools-report-bug.png"));
00129   dlg.setStandardButtons(QMessageBox::Ok);
00130 
00131   dlg.setText("<b>Vidalia encountered an error and needed to close</b>");
00132   dlg.setInformativeText(
00133     "<p>Vidalia attempted to automatically create an error report to "
00134     "help diagnose the problem, but was unable to do so. Please report "
00135     "this problem, along with what you were doing before Vidalia crashed, "
00136     "to the developers at:</p><p>"
00137     "<a href=\"https://trac.torproject.org/projects/tor/newticket\">"
00138     "https://trac.torproject.org/projects/tor/newticket</a></p> "
00139     "<p>Click \"Show Details\" below for information about the problem "
00140     "encountered.");
00141 
00142   dlg.setDetailedText(errorMessage);
00143   return dlg.exec();
00144 }