Vidalia 0.2.12
|
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 }