зеркало из https://github.com/mozilla/pjs.git
bug 378581 - merge platform implementations of crash reporter client. Patch by Dave Camp <dcamp@mozilla.com>, r=me
This commit is contained in:
Родитель
821f63b700
Коммит
5390815109
|
@ -53,8 +53,10 @@ DIST_FILES = crashreporter.ini
|
||||||
|
|
||||||
LOCAL_INCLUDES = -I$(srcdir)/../airbag/src
|
LOCAL_INCLUDES = -I$(srcdir)/../airbag/src
|
||||||
|
|
||||||
|
CPPSRCS = crashreporter.cpp
|
||||||
|
|
||||||
ifeq ($(OS_ARCH),WINNT)
|
ifeq ($(OS_ARCH),WINNT)
|
||||||
CPPSRCS = crashreporter_win.cpp
|
CPPSRCS += crashreporter_win.cpp
|
||||||
LIBS += \
|
LIBS += \
|
||||||
$(DEPTH)/toolkit/airbag/airbag/src/client/windows/sender/$(LIB_PREFIX)crash_report_sender_s.$(LIB_SUFFIX) \
|
$(DEPTH)/toolkit/airbag/airbag/src/client/windows/sender/$(LIB_PREFIX)crash_report_sender_s.$(LIB_SUFFIX) \
|
||||||
$(DEPTH)/toolkit/airbag/airbag/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX) \
|
$(DEPTH)/toolkit/airbag/airbag/src/common/windows/$(LIB_PREFIX)breakpad_windows_common_s.$(LIB_SUFFIX) \
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Mozilla Toolkit Crash Reporter
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* Mozilla Corporation
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2006-2007
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||||
|
* Dave Camp <dcamp@mozilla.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
#include "crashreporter.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::istream;
|
||||||
|
using std::ifstream;
|
||||||
|
using std::istringstream;
|
||||||
|
using std::ostream;
|
||||||
|
using std::ofstream;
|
||||||
|
|
||||||
|
StringTable gStrings;
|
||||||
|
int gArgc;
|
||||||
|
const char** gArgv;
|
||||||
|
|
||||||
|
static string gSendURL;
|
||||||
|
static string gDumpFile;
|
||||||
|
static string gExtraFile;
|
||||||
|
static string gSettingsPath;
|
||||||
|
static bool gDeleteDump = true;
|
||||||
|
|
||||||
|
|
||||||
|
static string kExtraDataExtension = ".extra";
|
||||||
|
|
||||||
|
static bool ReadStrings(istream &in, StringTable &strings)
|
||||||
|
{
|
||||||
|
string currentSection;
|
||||||
|
while (!in.eof()) {
|
||||||
|
string line;
|
||||||
|
std::getline(in, line);
|
||||||
|
int sep = line.find('=');
|
||||||
|
if (sep >= 0) {
|
||||||
|
string key, value;
|
||||||
|
key = line.substr(0, sep);
|
||||||
|
value = line.substr(sep + 1);
|
||||||
|
strings[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReadStringsFromFile(const string& path,
|
||||||
|
StringTable& strings)
|
||||||
|
{
|
||||||
|
ifstream f(path.c_str(), std::ios::in);
|
||||||
|
if (!f.is_open()) return false;
|
||||||
|
|
||||||
|
return ReadStrings(f, strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReadConfig()
|
||||||
|
{
|
||||||
|
string iniPath;
|
||||||
|
if (!UIGetIniPath(iniPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ReadStringsFromFile(iniPath, gStrings))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gSendURL = gStrings["URL"];
|
||||||
|
|
||||||
|
string deleteSetting = gStrings["Delete"];
|
||||||
|
gDeleteDump = deleteSetting.empty() || atoi(deleteSetting.c_str()) != 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string GetExtraDataFilename(const string& dumpfile)
|
||||||
|
{
|
||||||
|
string filename(dumpfile);
|
||||||
|
int dot = filename.rfind('.');
|
||||||
|
if (dot < 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
filename.replace(dot, filename.length() - dot, kExtraDataExtension);
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string Basename(const string& file)
|
||||||
|
{
|
||||||
|
int slashIndex = file.rfind(UI_DIR_SEPARATOR);
|
||||||
|
if (slashIndex >= 0)
|
||||||
|
return file.substr(slashIndex + 1);
|
||||||
|
else
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool MoveCrashData(const string& toDir,
|
||||||
|
string& dumpfile,
|
||||||
|
string& extrafile)
|
||||||
|
{
|
||||||
|
if (!UIEnsurePathExists(toDir)) {
|
||||||
|
UIError(toDir.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string newDump = toDir + UI_DIR_SEPARATOR + Basename(dumpfile);
|
||||||
|
string newExtra = toDir + UI_DIR_SEPARATOR + Basename(extrafile);
|
||||||
|
|
||||||
|
if (!UIMoveFile(dumpfile, newDump) ||
|
||||||
|
!UIMoveFile(extrafile, newExtra)) {
|
||||||
|
UIError(dumpfile.c_str());
|
||||||
|
UIError(newDump.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dumpfile = newDump;
|
||||||
|
extrafile = newExtra;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AddSubmittedReport(const string& serverResponse)
|
||||||
|
{
|
||||||
|
StringTable responseItems;
|
||||||
|
istringstream in(serverResponse);
|
||||||
|
ReadStrings(in, responseItems);
|
||||||
|
|
||||||
|
if (responseItems.find("CrashID") == responseItems.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string submittedDir =
|
||||||
|
gSettingsPath + UI_DIR_SEPARATOR + "submitted";
|
||||||
|
if (!UIEnsurePathExists(submittedDir)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = submittedDir + UI_DIR_SEPARATOR +
|
||||||
|
responseItems["CrashID"] + ".txt";
|
||||||
|
|
||||||
|
ofstream file(path.c_str());
|
||||||
|
if (!file.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
UI_SNPRINTF(buf, 1024,
|
||||||
|
gStrings["CrashID"].c_str(),
|
||||||
|
responseItems["CrashID"].c_str());
|
||||||
|
file << buf << "\n";
|
||||||
|
|
||||||
|
if (responseItems.find("ViewURL") != responseItems.end()) {
|
||||||
|
UI_SNPRINTF(buf, 1024,
|
||||||
|
gStrings["ViewURL"].c_str(),
|
||||||
|
responseItems["ViewURL"].c_str());
|
||||||
|
file << buf << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrashReporterSendCompleted(bool success,
|
||||||
|
const string& serverResponse)
|
||||||
|
{
|
||||||
|
if (success) {
|
||||||
|
if (gDeleteDump) {
|
||||||
|
if (!gDumpFile.empty())
|
||||||
|
UIDeleteFile(gDumpFile);
|
||||||
|
if (!gExtraFile.empty())
|
||||||
|
UIDeleteFile(gExtraFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddSubmittedReport(serverResponse);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char** argv)
|
||||||
|
{
|
||||||
|
gArgc = argc;
|
||||||
|
gArgv = argv;
|
||||||
|
|
||||||
|
if (!ReadConfig()) {
|
||||||
|
UIError("Couldn't read configuration");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UIInit())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
gDumpFile = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gDumpFile.empty()) {
|
||||||
|
// no dump file specified, run the default UI
|
||||||
|
UIShowDefaultUI();
|
||||||
|
} else {
|
||||||
|
gExtraFile = GetExtraDataFilename(gDumpFile);
|
||||||
|
if (gExtraFile.empty()) {
|
||||||
|
UIError("Couldn't get extra data filename");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringTable queryParameters;
|
||||||
|
if (!ReadStringsFromFile(gExtraFile, queryParameters)) {
|
||||||
|
UIError("Couldn't read extra data");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryParameters.find("ProductName") == queryParameters.end()) {
|
||||||
|
UIError("No product name specified");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string product = queryParameters["ProductName"];
|
||||||
|
string vendor = queryParameters["Vendor"];
|
||||||
|
if (!UIGetSettingsPath(vendor, product, gSettingsPath)) {
|
||||||
|
UIError("Couldn't get settings path");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
|
||||||
|
if (!MoveCrashData(pendingDir, gDumpFile, gExtraFile)) {
|
||||||
|
UIError("Couldn't move crash data");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIShowCrashUI(gDumpFile, queryParameters, gSendURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
UIShutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(XP_WIN) && !defined(__GNUC__)
|
||||||
|
// We need WinMain in order to not be a console app. This function is unused
|
||||||
|
// if we are a console application.
|
||||||
|
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
|
||||||
|
{
|
||||||
|
// Do the real work.
|
||||||
|
return main(__argc, (const char**)__argv);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef CRASHREPORTER_H__
|
||||||
|
#define CRASHREPORTER_H__
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if defined(XP_WIN32)
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#define UI_SNPRINTF _snprintf
|
||||||
|
#define UI_DIR_SEPARATOR "\\"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define UI_SNPRINTF snprintf
|
||||||
|
#define UI_DIR_SEPARATOR "/"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::string> StringTable;
|
||||||
|
|
||||||
|
#define ST_OK "Ok"
|
||||||
|
#define ST_CANCEL "Cancel"
|
||||||
|
#define ST_SEND "Send"
|
||||||
|
#define ST_DONTSEND "DontSend"
|
||||||
|
#define ST_CLOSE "Close"
|
||||||
|
#define ST_CRASHREPORTERTITLE "CrashReporterTitle"
|
||||||
|
#define ST_CRASHREPORTERDESCRIPTION "CrashReporterDescription"
|
||||||
|
#define ST_RADIOENABLE "RadioEnable"
|
||||||
|
#define ST_RADIODISABLE "RadioDisable"
|
||||||
|
#define ST_SENDTITLE "SendTitle"
|
||||||
|
#define ST_SUBMITSUCCESS "SubmitSuccess"
|
||||||
|
#define ST_SUBMITFAILED "SubmitFailed"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// implemented in crashreporter.cpp
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
extern StringTable gStrings;
|
||||||
|
extern int gArgc;
|
||||||
|
extern const char** gArgv;
|
||||||
|
|
||||||
|
// The UI finished sending the report
|
||||||
|
bool CrashReporterSendCompleted(bool success,
|
||||||
|
const std::string& serverResponse);
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// implemented in the platform-specific files
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
bool UIInit();
|
||||||
|
void UIShutdown();
|
||||||
|
|
||||||
|
// Run the UI for when the app was launched without a dump file
|
||||||
|
void UIShowDefaultUI();
|
||||||
|
|
||||||
|
// Run the UI for when the app was launched with a dump file
|
||||||
|
void UIShowCrashUI(const std::string& dumpfile,
|
||||||
|
const StringTable& queryParameters,
|
||||||
|
const std::string& sendURL);
|
||||||
|
|
||||||
|
void UIError(const std::string& message);
|
||||||
|
|
||||||
|
bool UIGetIniPath(std::string& path);
|
||||||
|
bool UIGetSettingsPath(const std::string& vendor,
|
||||||
|
const std::string& product,
|
||||||
|
std::string& settingsPath);
|
||||||
|
bool UIEnsurePathExists(const std::string& path);
|
||||||
|
bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
|
||||||
|
bool UIDeleteFile(const std::string& oldfile);
|
||||||
|
|
||||||
|
#endif
|
|
@ -41,9 +41,12 @@
|
||||||
|
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include "HTTPMultipartUpload.h"
|
#include "HTTPMultipartUpload.h"
|
||||||
|
#include "crashreporter.h"
|
||||||
|
|
||||||
@interface CrashReporterUI : NSObject
|
@interface CrashReporterUI : NSObject
|
||||||
{
|
{
|
||||||
|
IBOutlet NSWindow* window;
|
||||||
|
|
||||||
/* Enabled view */
|
/* Enabled view */
|
||||||
IBOutlet NSView* enableView;
|
IBOutlet NSView* enableView;
|
||||||
|
|
||||||
|
@ -59,16 +62,27 @@
|
||||||
IBOutlet NSProgressIndicator* progressBar;
|
IBOutlet NSProgressIndicator* progressBar;
|
||||||
IBOutlet NSButton* closeButton;
|
IBOutlet NSButton* closeButton;
|
||||||
|
|
||||||
|
/* Error view */
|
||||||
|
IBOutlet NSView* errorView;
|
||||||
|
IBOutlet NSTextField* errorLabel;
|
||||||
|
IBOutlet NSButton* errorCloseButton;
|
||||||
|
|
||||||
HTTPMultipartUpload *mPost;
|
HTTPMultipartUpload *mPost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)showDefaultUI;
|
||||||
|
- (void)showCrashUI:(const std::string&)dumpfile
|
||||||
|
queryParameters:(const StringTable&)queryParameters
|
||||||
|
sendURL:(const std::string&)sendURL;
|
||||||
|
- (void)showErrorUI:(const std::string&)dumpfile;
|
||||||
|
|
||||||
- (IBAction)closeClicked:(id)sender;
|
- (IBAction)closeClicked:(id)sender;
|
||||||
- (IBAction)sendClicked:(id)sender;
|
- (IBAction)sendClicked:(id)sender;
|
||||||
|
|
||||||
- (void)setView:(NSWindow *)w newView: (NSView *)v animate: (BOOL) animate;
|
- (void)setView:(NSWindow *)w newView: (NSView *)v animate: (BOOL) animate;
|
||||||
- (void)setupPost;
|
- (bool)setupPost;
|
||||||
- (void)uploadThread:(id)post;
|
- (void)uploadThread:(id)post;
|
||||||
- (void)uploadComplete:(id)error;
|
- (void)uploadComplete:(id)data;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -37,91 +37,79 @@
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include "crashreporter.h"
|
||||||
#include "crashreporter_osx.h"
|
#include "crashreporter_osx.h"
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <string>
|
#include <sys/types.h>
|
||||||
#include <map>
|
#include <fcntl.h>
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::map;
|
|
||||||
using std::ifstream;
|
|
||||||
|
|
||||||
typedef map<string,string> StringTable;
|
static NSAutoreleasePool* gMainPool;
|
||||||
typedef map<string,StringTable> StringTableSections;
|
static CrashReporterUI* gUI = 0;
|
||||||
|
static string gDumpFile;
|
||||||
|
static StringTable gQueryParameters;
|
||||||
|
static string gSendURL;
|
||||||
|
|
||||||
static string kExtraDataExtension = ".extra";
|
|
||||||
|
|
||||||
static string gMinidumpPath;
|
#define NSSTR(s) [NSString stringWithUTF8String:(s).c_str()]
|
||||||
static string gExtraDataPath;
|
|
||||||
static StringTableSections gStrings;
|
|
||||||
static StringTable gExtraData;
|
|
||||||
|
|
||||||
static BOOL gSendFailed;
|
|
||||||
|
|
||||||
static NSString *
|
static NSString *
|
||||||
Str(const char *aName, const char *aSection="Strings")
|
Str(const char* aName)
|
||||||
{
|
{
|
||||||
string str = gStrings[aSection][aName];
|
string str = gStrings[aName];
|
||||||
if (str.empty()) str = "?";
|
if (str.empty()) str = "?";
|
||||||
return [NSString stringWithUTF8String:str.c_str()];
|
return NSSTR(str);
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
ReadStrings(const string &aPath, StringTableSections *aSections)
|
|
||||||
{
|
|
||||||
StringTableSections §ions = *aSections;
|
|
||||||
|
|
||||||
ifstream f(aPath.c_str());
|
|
||||||
if (!f.is_open()) return false;
|
|
||||||
|
|
||||||
string currentSection;
|
|
||||||
while (!f.eof()) {
|
|
||||||
string line;
|
|
||||||
std::getline(f, line);
|
|
||||||
if (line[0] == ';') continue;
|
|
||||||
|
|
||||||
if (line[0] == '[') {
|
|
||||||
int close = line.find(']');
|
|
||||||
if (close >= 0)
|
|
||||||
currentSection = line.substr(1, close - 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sep = line.find('=');
|
|
||||||
if (sep >= 0)
|
|
||||||
sections[currentSection][line.substr(0, sep)] = line.substr(sep + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.eof();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation CrashReporterUI
|
@implementation CrashReporterUI
|
||||||
|
|
||||||
-(void)awakeFromNib
|
-(void)awakeFromNib
|
||||||
{
|
{
|
||||||
NSWindow *w = [descriptionLabel window];
|
gUI = self;
|
||||||
[w center];
|
[window center];
|
||||||
|
|
||||||
[w setTitle:[[NSBundle mainBundle]
|
[window setTitle:[[NSBundle mainBundle]
|
||||||
objectForInfoDictionaryKey:@"CFBundleName"]];
|
objectForInfoDictionaryKey:@"CFBundleName"]];
|
||||||
[descriptionLabel setStringValue:Str("CrashReporterDescription")];
|
[descriptionLabel setStringValue:Str(ST_CRASHREPORTERDESCRIPTION)];
|
||||||
[disableReportingButton setTitle:Str("RadioDisable")];
|
[disableReportingButton setTitle:Str(ST_RADIODISABLE)];
|
||||||
|
|
||||||
if (!gMinidumpPath.empty()) {
|
[closeButton setTitle:Str(ST_CLOSE)];
|
||||||
[sendButton setTitle:Str("Send")];
|
[errorCloseButton setTitle:Str(ST_CLOSE)];
|
||||||
[sendButton setKeyEquivalent:@"\r"];
|
|
||||||
[dontSendButton setTitle:Str("DontSend")];
|
|
||||||
} else {
|
|
||||||
[dontSendButton setFrame:[sendButton frame]];
|
|
||||||
[dontSendButton setTitle:Str("Close")];
|
|
||||||
[dontSendButton setKeyEquivalent:@"\r"];
|
|
||||||
[sendButton removeFromSuperview];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[closeButton setTitle:Str("Close")];
|
-(void)showDefaultUI
|
||||||
|
{
|
||||||
|
[dontSendButton setFrame:[sendButton frame]];
|
||||||
|
[dontSendButton setTitle:Str(ST_CLOSE)];
|
||||||
|
[dontSendButton setKeyEquivalent:@"\r"];
|
||||||
|
[sendButton removeFromSuperview];
|
||||||
|
|
||||||
[w makeKeyAndOrderFront:nil];
|
[window makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)showCrashUI:(const string&)dumpfile
|
||||||
|
queryParameters:(const StringTable&)queryParameters
|
||||||
|
sendURL:(const string&)sendURL
|
||||||
|
{
|
||||||
|
gDumpFile = dumpfile;
|
||||||
|
gQueryParameters = queryParameters;
|
||||||
|
gSendURL = sendURL;
|
||||||
|
|
||||||
|
[sendButton setTitle:Str(ST_SEND)];
|
||||||
|
[sendButton setKeyEquivalent:@"\r"];
|
||||||
|
[dontSendButton setTitle:Str(ST_DONTSEND)];
|
||||||
|
|
||||||
|
[window makeKeyAndOrderFront:nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)showErrorUI:(const string&)message
|
||||||
|
{
|
||||||
|
[errorLabel setStringValue: NSSTR(message)];
|
||||||
|
|
||||||
|
[self setView: window newView: errorView animate: NO];
|
||||||
|
[window makeKeyAndOrderFront:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(IBAction)closeClicked:(id)sender
|
-(IBAction)closeClicked:(id)sender
|
||||||
|
@ -131,21 +119,16 @@ ReadStrings(const string &aPath, StringTableSections *aSections)
|
||||||
|
|
||||||
-(IBAction)sendClicked:(id)sender
|
-(IBAction)sendClicked:(id)sender
|
||||||
{
|
{
|
||||||
NSWindow *w = [descriptionLabel window];
|
[self setView: window newView: uploadingView animate: YES];
|
||||||
|
|
||||||
[progressBar startAnimation: self];
|
[progressBar startAnimation: self];
|
||||||
[progressLabel setStringValue:Str("SendTitle")];
|
[progressLabel setStringValue:Str(ST_SENDTITLE)];
|
||||||
|
|
||||||
[self setupPost];
|
if (![self setupPost])
|
||||||
|
[NSApp terminate];
|
||||||
if (mPost) {
|
|
||||||
[self setView: w newView: uploadingView animate: YES];
|
|
||||||
[progressBar startAnimation: self];
|
|
||||||
|
|
||||||
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
[NSThread detachNewThreadSelector:@selector(uploadThread:)
|
||||||
toTarget:self
|
toTarget:self
|
||||||
withObject:nil];
|
withObject:mPost];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)setView:(NSWindow*)w newView: (NSView*)v animate: (BOOL)animate
|
-(void)setView:(NSWindow*)w newView: (NSView*)v animate: (BOOL)animate
|
||||||
|
@ -153,7 +136,7 @@ ReadStrings(const string &aPath, StringTableSections *aSections)
|
||||||
NSRect frame = [w frame];
|
NSRect frame = [w frame];
|
||||||
|
|
||||||
NSRect oldViewFrame = [[w contentView] frame];
|
NSRect oldViewFrame = [[w contentView] frame];
|
||||||
NSRect newViewFrame = [uploadingView frame];
|
NSRect newViewFrame = [v frame];
|
||||||
|
|
||||||
frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
|
frame.origin.y += oldViewFrame.size.height - newViewFrame.size.height;
|
||||||
frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height;
|
frame.size.height -= oldViewFrame.size.height - newViewFrame.size.height;
|
||||||
|
@ -165,109 +148,181 @@ ReadStrings(const string &aPath, StringTableSections *aSections)
|
||||||
[w setFrame: frame display: true animate: animate];
|
[w setFrame: frame display: true animate: animate];
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)setupPost
|
-(bool)setupPost
|
||||||
{
|
{
|
||||||
NSURL *url = [NSURL URLWithString:Str("URL", "Settings")];
|
NSURL* url = [NSURL URLWithString:NSSTR(gSendURL)];
|
||||||
if (!url) return;
|
if (!url) return false;
|
||||||
|
|
||||||
mPost = [[HTTPMultipartUpload alloc] initWithURL: url];
|
mPost = [[HTTPMultipartUpload alloc] initWithURL: url];
|
||||||
if (!mPost) return;
|
if (!mPost) return false;
|
||||||
|
|
||||||
NSMutableDictionary* parameters =
|
NSMutableDictionary* parameters =
|
||||||
[[NSMutableDictionary alloc] initWithCapacity: gExtraData.size()];
|
[[NSMutableDictionary alloc] initWithCapacity: gQueryParameters.size()];
|
||||||
|
if (!parameters) return false;
|
||||||
|
|
||||||
StringTable::const_iterator end = gExtraData.end();
|
StringTable::const_iterator end = gQueryParameters.end();
|
||||||
for (StringTable::const_iterator i = gExtraData.begin(); i != end; i++) {
|
for (StringTable::const_iterator i = gQueryParameters.begin();
|
||||||
NSString *key = [NSString stringWithUTF8String: i->first.c_str()];
|
i != end;
|
||||||
NSString *value = [NSString stringWithUTF8String: i->second.c_str()];
|
i++) {
|
||||||
|
NSString* key = NSSTR(i->first);
|
||||||
|
NSString* value = NSSTR(i->second);
|
||||||
[parameters setObject: value forKey: key];
|
[parameters setObject: value forKey: key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[mPost addFileAtPath: NSSTR(gDumpFile) name: @"upload_file_minidump"];
|
||||||
[mPost setParameters: parameters];
|
[mPost setParameters: parameters];
|
||||||
|
|
||||||
[mPost addFileAtPath: [NSString stringWithUTF8String: gMinidumpPath.c_str()]
|
return true;
|
||||||
name: @"upload_file_minidump"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)uploadComplete:(id)error
|
-(void)uploadComplete:(id)data
|
||||||
{
|
{
|
||||||
[progressBar stopAnimation: self];
|
[progressBar stopAnimation: self];
|
||||||
|
|
||||||
NSHTTPURLResponse* response = [mPost response];
|
NSHTTPURLResponse* response = [mPost response];
|
||||||
|
|
||||||
NSString* status;
|
NSString* status;
|
||||||
if (error || !response || [response statusCode] != 200) {
|
bool success;
|
||||||
status = Str("SubmitFailed");
|
string reply;
|
||||||
gSendFailed = YES;
|
if (!data || !response || [response statusCode] != 200) {
|
||||||
} else
|
status = Str(ST_SUBMITFAILED);
|
||||||
status = Str("SubmitSuccess");
|
success = false;
|
||||||
|
reply = "";
|
||||||
|
} else {
|
||||||
|
status = Str(ST_SUBMITSUCCESS);
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
NSString* encodingName = [response textEncodingName];
|
||||||
|
NSStringEncoding encoding;
|
||||||
|
if (encodingName) {
|
||||||
|
encoding = CFStringConvertEncodingToNSStringEncoding(
|
||||||
|
CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName));
|
||||||
|
} else {
|
||||||
|
encoding = NSISOLatin1StringEncoding;
|
||||||
|
}
|
||||||
|
NSString* r = [[NSString alloc] initWithData: data encoding: encoding];
|
||||||
|
reply = [r UTF8String];
|
||||||
|
}
|
||||||
|
|
||||||
[progressLabel setStringValue: status];
|
[progressLabel setStringValue: status];
|
||||||
[closeButton setEnabled: true];
|
[closeButton setEnabled: true];
|
||||||
[closeButton setKeyEquivalent:@"\r"];
|
[closeButton setKeyEquivalent:@"\r"];
|
||||||
|
|
||||||
|
CrashReporterSendCompleted(success, reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)uploadThread:(id)post
|
-(void)uploadThread:(id)post
|
||||||
{
|
{
|
||||||
NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init];
|
||||||
NSError* error = nil;
|
NSError* error = nil;
|
||||||
[mPost send: &error];
|
NSData* data = [post send: &error];
|
||||||
|
if (error)
|
||||||
|
data = nil;
|
||||||
|
|
||||||
[self performSelectorOnMainThread: @selector(uploadComplete:)
|
[self performSelectorOnMainThread: @selector(uploadComplete:)
|
||||||
withObject: error
|
withObject: data
|
||||||
waitUntilDone: nil];
|
waitUntilDone: YES];
|
||||||
|
|
||||||
[autoreleasepool release];
|
[autoreleasepool release];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
string
|
/* === Crashreporter UI Functions === */
|
||||||
GetExtraDataFilename(const string& dumpfile)
|
|
||||||
|
bool UIInit()
|
||||||
{
|
{
|
||||||
string filename(dumpfile);
|
gMainPool = [[NSAutoreleasePool alloc] init];
|
||||||
int dot = filename.rfind('.');
|
[NSApplication sharedApplication];
|
||||||
if (dot < 0)
|
[NSBundle loadNibNamed:@"MainMenu" owner:NSApp];
|
||||||
return "";
|
|
||||||
|
|
||||||
filename.replace(dot, filename.length() - dot, kExtraDataExtension);
|
return true;
|
||||||
return filename;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void UIShutdown()
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
{
|
||||||
NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
|
[gMainPool release];
|
||||||
string iniPath(argv[0]);
|
|
||||||
iniPath.append(".ini");
|
|
||||||
if (!ReadStrings(iniPath, &gStrings)) {
|
|
||||||
printf("couldn't read strings\n");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc > 1) {
|
void UIShowDefaultUI()
|
||||||
gMinidumpPath = argv[1];
|
{
|
||||||
gExtraDataPath = GetExtraDataFilename(gMinidumpPath);
|
[gUI showDefaultUI];
|
||||||
if (!gExtraDataPath.empty()) {
|
[NSApp run];
|
||||||
StringTableSections table;
|
|
||||||
ReadStrings(gExtraDataPath, &table);
|
|
||||||
gExtraData = table[""];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gSendFailed = NO;
|
void UIShowCrashUI(const string& dumpfile,
|
||||||
|
const StringTable& queryParameters,
|
||||||
int ret = NSApplicationMain(argc, (const char **) argv);
|
const string& sendURL)
|
||||||
|
{
|
||||||
string deleteSetting = gStrings["Settings"]["Delete"];
|
[gUI showCrashUI: dumpfile
|
||||||
if (!gSendFailed &&
|
queryParameters: queryParameters
|
||||||
(deleteSetting.empty() || atoi(deleteSetting.c_str()) > 0)) {
|
sendURL: sendURL];
|
||||||
remove(gMinidumpPath.c_str());
|
[NSApp run];
|
||||||
if (!gExtraDataPath.empty())
|
|
||||||
remove(gExtraDataPath.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[autoreleasepool release];
|
void UIError(const string& message)
|
||||||
|
{
|
||||||
return ret;
|
if (!gUI) {
|
||||||
|
// UI failed to initialize, printing is the best we can do
|
||||||
|
printf("Error: %s\n", message.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[gUI showErrorUI: message];
|
||||||
|
[NSApp run];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIGetIniPath(string& path)
|
||||||
|
{
|
||||||
|
path = gArgv[0];
|
||||||
|
path.append(".ini");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIGetSettingsPath(const string& vendor,
|
||||||
|
const string& product,
|
||||||
|
string& settingsPath)
|
||||||
|
{
|
||||||
|
NSArray* paths;
|
||||||
|
paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
|
||||||
|
NSUserDomainMask,
|
||||||
|
YES);
|
||||||
|
if ([paths count] < 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
NSString* destPath = [paths objectAtIndex:0];
|
||||||
|
|
||||||
|
// Note that MacOS ignores the vendor when creating the profile hierarchy -
|
||||||
|
// all application preferences directories live alongside one another in
|
||||||
|
// ~/Library/Application Support/
|
||||||
|
destPath = [destPath stringByAppendingPathComponent: NSSTR(product)];
|
||||||
|
destPath = [destPath stringByAppendingPathComponent: @"Crash Reports"];
|
||||||
|
|
||||||
|
settingsPath = [destPath UTF8String];
|
||||||
|
|
||||||
|
if (!UIEnsurePathExists(settingsPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIEnsurePathExists(const string& path)
|
||||||
|
{
|
||||||
|
int ret = mkdir(path.c_str(), S_IRWXU);
|
||||||
|
int e = errno;
|
||||||
|
if (ret == -1 && e != EEXIST)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIMoveFile(const string& file, const string& newfile)
|
||||||
|
{
|
||||||
|
return (rename(file.c_str(), newfile.c_str()) != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIDeleteFile(const string& file)
|
||||||
|
{
|
||||||
|
return (unlink(file.c_str()) != -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#undef WIN32_LEAN_AND_MEAN
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "crashreporter.h"
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <commctrl.h>
|
#include <commctrl.h>
|
||||||
#include <richedit.h>
|
#include <richedit.h>
|
||||||
|
@ -48,7 +50,6 @@
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "client/windows/sender/crash_report_sender.h"
|
#include "client/windows/sender/crash_report_sender.h"
|
||||||
#include "common/windows/string_utils-inl.h"
|
#include "common/windows/string_utils-inl.h"
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#define CRASH_REPORTER_KEY L"Software\\Mozilla\\Crash Reporter"
|
#define CRASH_REPORTER_KEY L"Software\\Mozilla\\Crash Reporter"
|
||||||
#define CRASH_REPORTER_VALUE L"Enabled"
|
#define CRASH_REPORTER_VALUE L"Enabled"
|
||||||
|
@ -58,68 +59,25 @@
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::wstring;
|
using std::wstring;
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::ifstream;
|
|
||||||
using std::ofstream;
|
|
||||||
|
|
||||||
|
static wstring UTF8ToWide(const string& utf8, bool *success = 0);
|
||||||
bool ReadConfig();
|
static string WideToUTF8(const wstring& wide, bool *success = 0);
|
||||||
BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam,
|
static DWORD WINAPI SendThreadProc(LPVOID param);
|
||||||
LPARAM lParam);
|
|
||||||
BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam,
|
|
||||||
LPARAM lParam);
|
|
||||||
HANDLE CreateSendThread(HWND hDlg, LPCTSTR dumpFile);
|
|
||||||
bool CheckCrashReporterEnabled(bool* enabled);
|
|
||||||
void SetCrashReporterEnabled(bool enabled);
|
|
||||||
bool SendCrashReport(wstring dumpFile,
|
|
||||||
const map<wstring,wstring>* query_parameters,
|
|
||||||
wstring* server_response);
|
|
||||||
DWORD WINAPI SendThreadProc(LPVOID param);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HWND hDlg;
|
HWND hDlg;
|
||||||
wstring dumpFile;
|
wstring dumpFile;
|
||||||
const map<wstring,wstring>* query_parameters;
|
const StringTable* query_parameters;
|
||||||
|
wstring send_url;
|
||||||
wstring* server_response;
|
wstring* server_response;
|
||||||
} SENDTHREADDATA;
|
} SENDTHREADDATA;
|
||||||
|
|
||||||
TCHAR sendURL[2048] = L"\0";
|
static wstring Str(const char* key)
|
||||||
bool deleteDump = true;
|
{
|
||||||
|
return UTF8ToWide(gStrings[key]);
|
||||||
|
}
|
||||||
|
|
||||||
// Sort of a hack to get l10n
|
static void DoInitCommonControls()
|
||||||
enum {
|
|
||||||
ST_OK,
|
|
||||||
ST_CANCEL,
|
|
||||||
ST_CRASHREPORTERTITLE,
|
|
||||||
ST_CRASHREPORTERDESCRIPTION,
|
|
||||||
ST_RADIOENABLE,
|
|
||||||
ST_RADIODISABLE,
|
|
||||||
ST_SENDTITLE,
|
|
||||||
ST_SUBMITSUCCESS,
|
|
||||||
ST_SUBMITFAILED,
|
|
||||||
ST_CRASHID,
|
|
||||||
ST_CRASHDETAILSURL,
|
|
||||||
NUM_STRINGS
|
|
||||||
};
|
|
||||||
|
|
||||||
LPCTSTR stringNames[] = {
|
|
||||||
L"Ok",
|
|
||||||
L"Cancel",
|
|
||||||
L"CrashReporterTitle",
|
|
||||||
L"CrashReporterDescription",
|
|
||||||
L"RadioEnable",
|
|
||||||
L"RadioDisable",
|
|
||||||
L"SendTitle",
|
|
||||||
L"SubmitSuccess",
|
|
||||||
L"SubmitFailed",
|
|
||||||
L"CrashID",
|
|
||||||
L"CrashDetailsURL"
|
|
||||||
};
|
|
||||||
|
|
||||||
LPTSTR strings[NUM_STRINGS];
|
|
||||||
|
|
||||||
const wchar_t* kExtraDataExtension = L".extra";
|
|
||||||
|
|
||||||
void DoInitCommonControls()
|
|
||||||
{
|
{
|
||||||
INITCOMMONCONTROLSEX ic;
|
INITCOMMONCONTROLSEX ic;
|
||||||
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
|
||||||
|
@ -129,77 +87,15 @@ void DoInitCommonControls()
|
||||||
LoadLibrary(L"riched20.dll");
|
LoadLibrary(L"riched20.dll");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoadStrings(LPCTSTR fileName)
|
static BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
|
||||||
for (int i=ST_OK; i<NUM_STRINGS; i++) {
|
|
||||||
strings[i] = new TCHAR[1024];
|
|
||||||
GetPrivateProfileString(L"Strings", stringNames[i], L"", strings[i], 1024, fileName);
|
|
||||||
if (stringNames[i][0] == '\0')
|
|
||||||
return false;
|
|
||||||
//XXX should probably check for strings > 1024...
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetSettingsPath(wstring vendor, wstring product,
|
|
||||||
wstring& settings_path)
|
|
||||||
{
|
|
||||||
wchar_t path[MAX_PATH];
|
|
||||||
if(SUCCEEDED(SHGetFolderPath(NULL,
|
|
||||||
CSIDL_APPDATA,
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
path))) {
|
|
||||||
if (!vendor.empty()) {
|
|
||||||
PathAppend(path, vendor.c_str());
|
|
||||||
}
|
|
||||||
PathAppend(path, product.c_str());
|
|
||||||
PathAppend(path, L"Crash Reports");
|
|
||||||
// in case it doesn't exist
|
|
||||||
CreateDirectory(path, NULL);
|
|
||||||
settings_path = path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EnsurePathExists(wstring base_path, wstring sub_path)
|
|
||||||
{
|
|
||||||
wstring path = base_path + L"\\" + sub_path;
|
|
||||||
return CreateDirectory(path.c_str(), NULL) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadConfig()
|
|
||||||
{
|
|
||||||
TCHAR fileName[MAX_PATH];
|
|
||||||
|
|
||||||
if (GetModuleFileName(NULL, fileName, MAX_PATH)) {
|
|
||||||
// get crashreporter ini
|
|
||||||
LPTSTR s = wcsrchr(fileName, '.');
|
|
||||||
if (s) {
|
|
||||||
wcscpy(s, L".ini");
|
|
||||||
|
|
||||||
GetPrivateProfileString(L"Settings", L"URL", L"", sendURL, 2048, fileName);
|
|
||||||
|
|
||||||
TCHAR tmp[16];
|
|
||||||
GetPrivateProfileString(L"Settings", L"Delete", L"1", tmp, 16, fileName);
|
|
||||||
deleteDump = _wtoi(tmp) > 0;
|
|
||||||
|
|
||||||
return LoadStrings(fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
||||||
{
|
{
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
SetWindowText(hwndDlg, strings[ST_CRASHREPORTERTITLE]);
|
SetWindowText(hwndDlg, Str(ST_CRASHREPORTERTITLE).c_str());
|
||||||
SetDlgItemText(hwndDlg, IDOK, strings[ST_OK]);
|
SetDlgItemText(hwndDlg, IDOK, Str(ST_OK).c_str());
|
||||||
SetDlgItemText(hwndDlg, IDC_RADIOENABLE, strings[ST_RADIOENABLE]);
|
SetDlgItemText(hwndDlg, IDC_RADIOENABLE, Str(ST_RADIOENABLE).c_str());
|
||||||
SetDlgItemText(hwndDlg, IDC_RADIODISABLE, strings[ST_RADIODISABLE]);
|
SetDlgItemText(hwndDlg, IDC_RADIODISABLE, Str(ST_RADIODISABLE).c_str());
|
||||||
SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, strings[ST_CRASHREPORTERDESCRIPTION]);
|
SetDlgItemText(hwndDlg, IDC_DESCRIPTIONTEXT, Str(ST_CRASHREPORTERDESCRIPTION).c_str());
|
||||||
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
|
SendDlgItemMessage(hwndDlg, IDC_DESCRIPTIONTEXT, EM_SETTARGETDEVICE, (WPARAM)NULL, 0);
|
||||||
SetFocus(GetDlgItem(hwndDlg, IDC_RADIOENABLE));
|
SetFocus(GetDlgItem(hwndDlg, IDC_RADIOENABLE));
|
||||||
CheckRadioButton(hwndDlg, IDC_RADIOENABLE, IDC_RADIODISABLE, lParam ? IDC_RADIOENABLE : IDC_RADIODISABLE);
|
CheckRadioButton(hwndDlg, IDC_RADIOENABLE, IDC_RADIODISABLE, lParam ? IDC_RADIOENABLE : IDC_RADIODISABLE);
|
||||||
|
@ -218,7 +114,7 @@ BOOL CALLBACK EnableDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetRegValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
|
static bool GetRegValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
|
||||||
{
|
{
|
||||||
DWORD type, dataSize;
|
DWORD type, dataSize;
|
||||||
dataSize = sizeof(DWORD);
|
dataSize = sizeof(DWORD);
|
||||||
|
@ -229,7 +125,7 @@ bool GetRegValue(HKEY hRegKey, LPCTSTR valueName, DWORD* value)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckCrashReporterEnabled(bool* enabled)
|
static bool CheckCrashReporterEnabled(bool* enabled)
|
||||||
{
|
{
|
||||||
*enabled = false;
|
*enabled = false;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
@ -263,7 +159,7 @@ bool CheckCrashReporterEnabled(bool* enabled)
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCrashReporterEnabled(bool enabled)
|
static void SetCrashReporterEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
HKEY hRegKey;
|
HKEY hRegKey;
|
||||||
if (RegCreateKey(HKEY_CURRENT_USER, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS) {
|
if (RegCreateKey(HKEY_CURRENT_USER, CRASH_REPORTER_KEY, &hRegKey) == ERROR_SUCCESS) {
|
||||||
|
@ -273,7 +169,7 @@ void SetCrashReporterEnabled(bool enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
static BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
static bool finishedOk = false;
|
static bool finishedOk = false;
|
||||||
static HANDLE hThread = NULL;
|
static HANDLE hThread = NULL;
|
||||||
|
@ -282,8 +178,8 @@ BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM l
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
{
|
{
|
||||||
//init strings
|
//init strings
|
||||||
SetWindowText(hwndDlg, strings[ST_SENDTITLE]);
|
SetWindowText(hwndDlg, Str(ST_SENDTITLE).c_str());
|
||||||
SetDlgItemText(hwndDlg, IDCANCEL, strings[ST_CANCEL]);
|
SetDlgItemText(hwndDlg, IDCANCEL, Str(ST_CANCEL).c_str());
|
||||||
// init progressmeter
|
// init progressmeter
|
||||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
|
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0);
|
||||||
|
@ -299,10 +195,16 @@ BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM l
|
||||||
finishedOk = (wParam == 1);
|
finishedOk = (wParam == 1);
|
||||||
if (finishedOk) {
|
if (finishedOk) {
|
||||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 100, 0);
|
SendDlgItemMessage(hwndDlg, IDC_PROGRESS, PBM_SETPOS, 100, 0);
|
||||||
MessageBox(hwndDlg, strings[ST_SUBMITSUCCESS], strings[ST_CRASHREPORTERTITLE], MB_OK | MB_ICONINFORMATION);
|
MessageBox(hwndDlg,
|
||||||
|
Str(ST_SUBMITSUCCESS).c_str(),
|
||||||
|
Str(ST_CRASHREPORTERTITLE).c_str(),
|
||||||
|
MB_OK | MB_ICONINFORMATION);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MessageBox(hwndDlg, strings[ST_SUBMITFAILED], strings[ST_CRASHREPORTERTITLE], MB_OK | MB_ICONERROR);
|
MessageBox(hwndDlg,
|
||||||
|
Str(ST_SUBMITFAILED).c_str(),
|
||||||
|
Str(ST_CRASHREPORTERTITLE).c_str(),
|
||||||
|
MB_OK | MB_ICONERROR);
|
||||||
}
|
}
|
||||||
EndDialog(hwndDlg, finishedOk ? 1 : 0);
|
EndDialog(hwndDlg, finishedOk ? 1 : 0);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -318,14 +220,16 @@ BOOL CALLBACK SendDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendCrashReport(wstring dumpFile,
|
static bool SendCrashReport(wstring dumpFile,
|
||||||
const map<wstring,wstring>* query_parameters,
|
const StringTable* query_parameters,
|
||||||
|
wstring send_url,
|
||||||
wstring* server_response)
|
wstring* server_response)
|
||||||
{
|
{
|
||||||
SENDTHREADDATA td;
|
SENDTHREADDATA td;
|
||||||
td.hDlg = NULL;
|
td.hDlg = NULL;
|
||||||
td.dumpFile = dumpFile;
|
td.dumpFile = dumpFile;
|
||||||
td.query_parameters = query_parameters;
|
td.query_parameters = query_parameters;
|
||||||
|
td.send_url = send_url;
|
||||||
td.server_response = server_response;
|
td.server_response = server_response;
|
||||||
|
|
||||||
int res = (int)DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
|
int res = (int)DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_SENDDIALOG), NULL,
|
||||||
|
@ -334,20 +238,26 @@ bool SendCrashReport(wstring dumpFile,
|
||||||
return (res >= 0);
|
return (res >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI SendThreadProc(LPVOID param)
|
static DWORD WINAPI SendThreadProc(LPVOID param)
|
||||||
{
|
{
|
||||||
bool finishedOk;
|
bool finishedOk;
|
||||||
SENDTHREADDATA* td = (SENDTHREADDATA*)param;
|
SENDTHREADDATA* td = (SENDTHREADDATA*)param;
|
||||||
|
|
||||||
wstring url(sendURL);
|
if (td->send_url.empty()) {
|
||||||
|
|
||||||
if (url.empty()) {
|
|
||||||
finishedOk = false;
|
finishedOk = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
map<wstring,wstring>query_parameters;
|
||||||
|
StringTable::const_iterator end = td->query_parameters->end();
|
||||||
|
for (StringTable::const_iterator i = td->query_parameters->begin();
|
||||||
|
i != end;
|
||||||
|
i++) {
|
||||||
|
query_parameters[UTF8ToWide(i->first)] = UTF8ToWide(i->second);
|
||||||
|
}
|
||||||
|
|
||||||
finishedOk = (google_breakpad::CrashReportSender
|
finishedOk = (google_breakpad::CrashReportSender
|
||||||
::SendCrashReport(url,
|
::SendCrashReport(td->send_url,
|
||||||
*(td->query_parameters),
|
query_parameters,
|
||||||
td->dumpFile,
|
td->dumpFile,
|
||||||
td->server_response)
|
td->server_response)
|
||||||
== google_breakpad::RESULT_SUCCEEDED);
|
== google_breakpad::RESULT_SUCCEEDED);
|
||||||
|
@ -357,168 +267,79 @@ DWORD WINAPI SendThreadProc(LPVOID param)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConvertUTF8ToWide(const char* utf8_string, wstring& ucs2_string)
|
static wstring UTF8ToWide(const string& utf8, bool *success)
|
||||||
{
|
{
|
||||||
wchar_t* buffer = NULL;
|
wchar_t* buffer = NULL;
|
||||||
int buffer_size = MultiByteToWideChar(CP_UTF8, 0, utf8_string,
|
int buffer_size = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(),
|
||||||
-1, NULL, 0);
|
-1, NULL, 0);
|
||||||
if(buffer_size == 0)
|
if(buffer_size == 0) {
|
||||||
return false;
|
if (success)
|
||||||
|
*success = false;
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
buffer = new wchar_t[buffer_size];
|
buffer = new wchar_t[buffer_size];
|
||||||
if(buffer == NULL)
|
if(buffer == NULL) {
|
||||||
return false;
|
if (success)
|
||||||
|
*success = false;
|
||||||
MultiByteToWideChar(CP_UTF8, 0, utf8_string,
|
return L"";
|
||||||
-1, buffer, buffer_size);
|
|
||||||
ucs2_string = buffer;
|
|
||||||
delete [] buffer;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConvertWideToUTF8(const wchar_t* ucs2_string, string& utf8_string)
|
MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(),
|
||||||
|
-1, buffer, buffer_size);
|
||||||
|
wstring str = buffer;
|
||||||
|
delete [] buffer;
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
*success = true;
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string WideToUTF8(const wstring& wide, bool *success)
|
||||||
{
|
{
|
||||||
char* buffer = NULL;
|
char* buffer = NULL;
|
||||||
int buffer_size = WideCharToMultiByte(CP_UTF8, 0, ucs2_string,
|
int buffer_size = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(),
|
||||||
-1, NULL, 0, NULL, NULL);
|
-1, NULL, 0, NULL, NULL);
|
||||||
if(buffer_size == 0)
|
if(buffer_size == 0) {
|
||||||
return false;
|
if (success)
|
||||||
|
*success = false;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
buffer = new char[buffer_size];
|
buffer = new char[buffer_size];
|
||||||
if(buffer == NULL)
|
if(buffer == NULL) {
|
||||||
return false;
|
if (success)
|
||||||
|
*success = false;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, ucs2_string,
|
WideCharToMultiByte(CP_UTF8, 0, wide.c_str(),
|
||||||
-1, buffer, buffer_size, NULL, NULL);
|
-1, buffer, buffer_size, NULL, NULL);
|
||||||
utf8_string = buffer;
|
string utf8 = buffer;
|
||||||
delete [] buffer;
|
delete [] buffer;
|
||||||
return true;
|
|
||||||
|
if (success)
|
||||||
|
*success = true;
|
||||||
|
|
||||||
|
return utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadKeyValuePairs(const wstring& data,
|
/* === Crashreporter UI Functions === */
|
||||||
map<wstring, wstring>& values)
|
|
||||||
|
bool UIInit()
|
||||||
{
|
{
|
||||||
if (data.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
string line;
|
|
||||||
int line_begin = 0;
|
|
||||||
int line_end = data.find('\n');
|
|
||||||
while(line_end >= 0) {
|
|
||||||
int pos = data.find('=', line_begin);
|
|
||||||
if (pos >= 0 && pos < line_end) {
|
|
||||||
wstring key, value;
|
|
||||||
key = data.substr(line_begin, pos - line_begin);
|
|
||||||
value = data.substr(pos + 1, line_end - pos - 1);
|
|
||||||
values[key] = value;
|
|
||||||
}
|
|
||||||
line_begin = line_end + 1;
|
|
||||||
line_end = data.find('\n', line_begin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ReadExtraData(const wstring& filename,
|
|
||||||
map<wstring, wstring>& query_parameters)
|
|
||||||
{
|
|
||||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
|
||||||
ifstream file;
|
|
||||||
file.open(filename.c_str(), std::ios::in);
|
|
||||||
#else // _MSC_VER >= 1400
|
|
||||||
ifstream file(_wfopen(filename.c_str(), L"rb"));
|
|
||||||
#endif // _MSC_VER >= 1400
|
|
||||||
if (!file.is_open())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
wstring data;
|
|
||||||
char* buf;
|
|
||||||
file.seekg(0, std::ios::end);
|
|
||||||
int file_size = file.tellg();
|
|
||||||
file.seekg(0, std::ios::beg);
|
|
||||||
buf = new char[file_size+1];
|
|
||||||
if (!buf)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
file.read(buf, file_size);
|
|
||||||
buf[file_size] ='\0';
|
|
||||||
ConvertUTF8ToWide(buf, data);
|
|
||||||
delete buf;
|
|
||||||
|
|
||||||
ReadKeyValuePairs(data, query_parameters);
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring GetExtraDataFilename(const wstring& dumpfile)
|
|
||||||
{
|
|
||||||
wstring filename(dumpfile);
|
|
||||||
int dot = filename.rfind('.');
|
|
||||||
if (dot < 0)
|
|
||||||
return L"";
|
|
||||||
|
|
||||||
filename.replace(dot, filename.length() - dot, kExtraDataExtension);
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AddSubmittedReport(wstring settings_path, wstring server_response)
|
|
||||||
{
|
|
||||||
map<wstring, wstring> response_items;
|
|
||||||
ReadKeyValuePairs(server_response, response_items);
|
|
||||||
|
|
||||||
if (response_items.find(L"CrashID") == response_items.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
wstring submitted_path = settings_path + L"\\submitted\\" +
|
|
||||||
response_items[L"CrashID"] + L".txt";
|
|
||||||
|
|
||||||
#if _MSC_VER >= 1400 // MSVC 2005/8
|
|
||||||
ofstream file;
|
|
||||||
file.open(submitted_path.c_str(), std::ios::out);
|
|
||||||
#else // _MSC_VER >= 1400
|
|
||||||
ofstream file(_wfopen(submitted_path.c_str(), L"wb"));
|
|
||||||
#endif // _MSC_VER >= 1400
|
|
||||||
if (!file.is_open())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
wchar_t buf[1024];
|
|
||||||
wsprintf(buf, strings[ST_CRASHID], response_items[L"CrashID"].c_str());
|
|
||||||
wstring data = buf;
|
|
||||||
data += L"\n";
|
|
||||||
if (response_items.find(L"ViewURL") != response_items.end()) {
|
|
||||||
wsprintf(buf, strings[ST_CRASHDETAILSURL],
|
|
||||||
response_items[L"ViewURL"].c_str());
|
|
||||||
data += buf;
|
|
||||||
data += L"\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
string utf8_data;
|
|
||||||
if (!ConvertWideToUTF8(data.c_str(), utf8_data))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
file << utf8_data;
|
|
||||||
file.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
map<wstring,wstring> query_parameters;
|
|
||||||
|
|
||||||
DoInitCommonControls();
|
DoInitCommonControls();
|
||||||
if (!ReadConfig()) {
|
return true;
|
||||||
MessageBox(NULL, L"Missing crashreporter.ini file", L"Crash Reporter Error", MB_OK | MB_ICONSTOP);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring dumpfile;
|
void UIShutdown()
|
||||||
bool enabled = false;
|
{
|
||||||
|
|
||||||
if (argc > 1) {
|
|
||||||
if (!ConvertUTF8ToWide(argv[1], dumpfile))
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumpfile.empty()) {
|
void UIShowDefaultUI()
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
// no dump file specified, just ask about enabling
|
// no dump file specified, just ask about enabling
|
||||||
if (!CheckCrashReporterEnabled(&enabled))
|
if (!CheckCrashReporterEnabled(&enabled))
|
||||||
enabled = true;
|
enabled = true;
|
||||||
|
@ -526,47 +347,12 @@ int main(int argc, char **argv)
|
||||||
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)enabled));
|
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)enabled));
|
||||||
SetCrashReporterEnabled(enabled);
|
SetCrashReporterEnabled(enabled);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
wstring extrafile = GetExtraDataFilename(dumpfile);
|
|
||||||
if (!extrafile.empty()) {
|
|
||||||
ReadExtraData(extrafile, query_parameters);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//XXX: print error message
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query_parameters.find(L"ProductName") == query_parameters.end()) {
|
|
||||||
//XXX: print error message
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring product = query_parameters[L"ProductName"];
|
|
||||||
wstring vendor;
|
|
||||||
if (query_parameters.find(L"Vendor") != query_parameters.end()) {
|
|
||||||
vendor = query_parameters[L"Vendor"];
|
|
||||||
}
|
|
||||||
wstring settings_path;
|
|
||||||
|
|
||||||
if(!GetSettingsPath(vendor, product, settings_path)) {
|
|
||||||
//XXX: print error message
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnsurePathExists(settings_path, L"pending");
|
|
||||||
EnsurePathExists(settings_path, L"submitted");
|
|
||||||
|
|
||||||
// now we move the crash report and extra data to pending
|
|
||||||
wstring newfile = settings_path + L"\\pending\\" +
|
|
||||||
google_breakpad::WindowsStringUtils::GetBaseName(dumpfile);
|
|
||||||
MoveFile(dumpfile.c_str(), newfile.c_str());
|
|
||||||
dumpfile = newfile;
|
|
||||||
|
|
||||||
newfile = settings_path + L"\\pending\\" +
|
|
||||||
google_breakpad::WindowsStringUtils::GetBaseName(extrafile);
|
|
||||||
MoveFile(extrafile.c_str(), newfile.c_str());
|
|
||||||
extrafile = newfile;
|
|
||||||
|
|
||||||
|
void UIShowCrashUI(const string& dumpfile,
|
||||||
|
const StringTable& query_parameters,
|
||||||
|
const string& send_url)
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
if (!CheckCrashReporterEnabled(&enabled)) {
|
if (!CheckCrashReporterEnabled(&enabled)) {
|
||||||
//ask user if crash reporter should be enabled
|
//ask user if crash reporter should be enabled
|
||||||
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)true));
|
enabled = (1 == DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_ENABLEDIALOG), NULL, (DLGPROC)EnableDialogProc, (LPARAM)true));
|
||||||
|
@ -575,25 +361,79 @@ int main(int argc, char **argv)
|
||||||
// if enabled, send crash report
|
// if enabled, send crash report
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
wstring server_response;
|
wstring server_response;
|
||||||
if (SendCrashReport(dumpfile, &query_parameters, &server_response)) {
|
bool success = SendCrashReport(UTF8ToWide(dumpfile),
|
||||||
if (deleteDump) {
|
&query_parameters,
|
||||||
DeleteFile(dumpfile.c_str());
|
UTF8ToWide(send_url),
|
||||||
if (!extrafile.empty())
|
&server_response);
|
||||||
DeleteFile(extrafile.c_str());
|
CrashReporterSendCompleted(success, WideToUTF8(server_response));
|
||||||
}
|
|
||||||
AddSubmittedReport(settings_path, server_response);
|
|
||||||
}
|
|
||||||
//TODO: show details?
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(XP_WIN) && !defined(__GNUC__)
|
void UIError(const string& message)
|
||||||
// We need WinMain in order to not be a console app. This function is unused
|
|
||||||
// if we are a console application.
|
|
||||||
int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
|
|
||||||
{
|
{
|
||||||
// Do the real work.
|
wstring title = Str(ST_CRASHREPORTERTITLE);
|
||||||
return main(__argc, __argv);
|
if (title.empty())
|
||||||
|
title = L"Crash Reporter Error";
|
||||||
|
|
||||||
|
MessageBox(NULL, UTF8ToWide(message).c_str(), title.c_str(),
|
||||||
|
MB_OK | MB_ICONSTOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIGetIniPath(string& path)
|
||||||
|
{
|
||||||
|
wchar_t fileName[MAX_PATH];
|
||||||
|
if (GetModuleFileName(NULL, fileName, MAX_PATH)) {
|
||||||
|
// get crashreporter ini
|
||||||
|
wchar_t* s = wcsrchr(fileName, '.');
|
||||||
|
if (s) {
|
||||||
|
wcscpy(s, L".ini");
|
||||||
|
path = WideToUTF8(fileName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIGetSettingsPath(const string& vendor,
|
||||||
|
const string& product,
|
||||||
|
string& settings_path)
|
||||||
|
{
|
||||||
|
wchar_t path[MAX_PATH];
|
||||||
|
if(SUCCEEDED(SHGetFolderPath(NULL,
|
||||||
|
CSIDL_APPDATA,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
path))) {
|
||||||
|
if (!vendor.empty()) {
|
||||||
|
PathAppend(path, UTF8ToWide(vendor).c_str());
|
||||||
|
}
|
||||||
|
PathAppend(path, UTF8ToWide(product).c_str());
|
||||||
|
PathAppend(path, L"Crash Reports");
|
||||||
|
// in case it doesn't exist
|
||||||
|
CreateDirectory(path, NULL);
|
||||||
|
settings_path = WideToUTF8(path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIEnsurePathExists(const string& path)
|
||||||
|
{
|
||||||
|
if (CreateDirectory(UTF8ToWide(path).c_str(), NULL) == 0) {
|
||||||
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIMoveFile(const string& oldfile, const string& newfile)
|
||||||
|
{
|
||||||
|
return MoveFile(UTF8ToWide(oldfile).c_str(), UTF8ToWide(newfile).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UIDeleteFile(const string& oldfile)
|
||||||
|
{
|
||||||
|
return DeleteFile(UTF8ToWide(oldfile).c_str());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,10 +10,14 @@
|
||||||
disableReportingButton = NSButton;
|
disableReportingButton = NSButton;
|
||||||
dontSendButton = NSButton;
|
dontSendButton = NSButton;
|
||||||
enableView = NSView;
|
enableView = NSView;
|
||||||
|
errorCloseButton = NSButton;
|
||||||
|
errorLabel = NSTextField;
|
||||||
|
errorView = NSView;
|
||||||
progressBar = NSProgressIndicator;
|
progressBar = NSProgressIndicator;
|
||||||
progressLabel = NSTextField;
|
progressLabel = NSTextField;
|
||||||
sendButton = NSButton;
|
sendButton = NSButton;
|
||||||
uploadingView = NSView;
|
uploadingView = NSView;
|
||||||
|
window = NSWindow;
|
||||||
};
|
};
|
||||||
SUPERCLASS = NSObject;
|
SUPERCLASS = NSObject;
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,11 +7,13 @@
|
||||||
<key>IBEditorPositions</key>
|
<key>IBEditorPositions</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>282</key>
|
<key>282</key>
|
||||||
<string>445 520 550 163 0 0 1440 878 </string>
|
<string>24 681 550 163 0 0 1440 878 </string>
|
||||||
<key>29</key>
|
<key>29</key>
|
||||||
<string>447 315 137 44 0 0 1440 878 </string>
|
<string>447 315 137 44 0 0 1440 878 </string>
|
||||||
<key>356</key>
|
<key>356</key>
|
||||||
<string>643 213 551 213 0 0 1440 878 </string>
|
<string>643 213 551 213 0 0 1440 878 </string>
|
||||||
|
<key>386</key>
|
||||||
|
<string>23 537 456 145 0 0 1440 878 </string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>IBFramework Version</key>
|
<key>IBFramework Version</key>
|
||||||
<string>446.1</string>
|
<string>446.1</string>
|
||||||
|
@ -24,9 +26,10 @@
|
||||||
<integer>2</integer>
|
<integer>2</integer>
|
||||||
<key>IBOpenObjects</key>
|
<key>IBOpenObjects</key>
|
||||||
<array>
|
<array>
|
||||||
<integer>21</integer>
|
<integer>386</integer>
|
||||||
<integer>29</integer>
|
|
||||||
<integer>282</integer>
|
<integer>282</integer>
|
||||||
|
<integer>29</integer>
|
||||||
|
<integer>21</integer>
|
||||||
</array>
|
</array>
|
||||||
<key>IBSystem Version</key>
|
<key>IBSystem Version</key>
|
||||||
<string>8P2137</string>
|
<string>8P2137</string>
|
||||||
|
|
Двоичные данные
toolkit/airbag/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
сгенерированный
Двоичные данные
toolkit/airbag/client/macbuild/Contents/Resources/English.lproj/MainMenu.nib/keyedobjects.nib
сгенерированный
Двоичный файл не отображается.
Загрузка…
Ссылка в новой задаче