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