xref: /aoo41x/main/crashrep/source/win32/soreport.cpp (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #define UNICODE
29 #define WIN32_LEAN_AND_MEAN
30 #if defined _MSC_VER
31 #pragma warning(push, 1)
32 #pragma warning(disable:4917)
33 #endif
34 #include <windows.h>
35 #include <windowsx.h>
36 
37 #include <mapi.h>
38 #include <commctrl.h>
39 #include <commdlg.h>
40 #include <psapi.h>
41 
42 #include <shellapi.h>
43 #include <shlobj.h>
44 
45 #define _UNICODE
46 #include <tchar.h>
47 
48 #define _RICHEDIT_VER	0x0200
49 #include <richedit.h>
50 
51 #if defined _MSC_VER
52 #pragma warning(pop)
53 #endif
54 
55 #if _RICHEDIT_VER >= 0x0200
56 #define RICHEDIT	TEXT("riched20.dll")
57 #else
58 #define RICHEDIT	TEXT("riched32.dll")
59 #endif
60 
61 #include <systools/win32/uwinapi.h>
62 #include <rtl/digest.h>
63 #include <rtl/bootstrap.hxx>
64 #include <osl/file.hxx>
65 #include <osl/process.h>
66 
67 #include <stdlib.h>
68 #include <stdio.h>
69 #include <io.h>
70 #include <fcntl.h>
71 #include <string>
72 #include <hash_map>
73 #include <winsock.h>
74 #include <malloc.h>
75 #include <process.h>
76 
77 #include <_version.h>
78 
79 #include "resource.h"
80 #include "base64.h"
81 
82 #define FORMATBUFSIZE	(8*1024)
83 #define MAX_TEXT_BUFFER (32*1024-1)
84 #define MAX_HOSTNAME	(1024)
85 
86 #ifdef __MINGW32__
87 #include <imagehlp.h>
88 #else
89 #include <dbghelp.h>
90 #endif
91 
92 #ifdef _UNICODE
93 #define tstring	wstring
94 #else
95 #define tstring string
96 #endif
97 
98 using namespace ::std;
99 
100 
101 wstring  g_wstrProductKey;
102 string  g_strDefaultLanguage;
103 FILE	*g_fpStackFile = NULL;
104 FILE	*g_fpChecksumFile = NULL;
105 DWORD	g_dwExceptionCode = 0;
106 
107 CHAR	g_szReportServerA[MAX_HOSTNAME] = "";
108 USHORT	g_uReportPort = 80;
109 
110 TCHAR	g_szBuildId[256] = TEXT("");
111 
112 TCHAR	g_szDumpFileName[MAX_PATH] = TEXT("");
113 
114 CHAR	g_szDumpFileNameA[MAX_PATH] = "";
115 CHAR	g_szCommentFileNameA[MAX_PATH] = "";
116 CHAR	g_szReportFileNameA[MAX_PATH] = "";
117 
118 
119 bool	g_bNoUserInterface = false;
120 bool	g_bSendReport = false;
121 bool	g_bLoadReport = false;
122 
123 #define REPORT_SERVER	g_szReportServerA
124 #define REPORT_PORT		g_uReportPort
125 
126 
127 //***************************************************************************
128 // tmpfile from msvcrt creates the temporary file in the root of the current
129 // volume and can fail.
130 
131 static FILE *_xfopen( const _TCHAR *file, const _TCHAR *mode )
132 {
133 #ifdef UNICODE
134 	if ( (LONG)GetVersion() < 0 )
135 	{
136 		char	afile[MAX_PATH];
137 		char	amode[16];
138 
139 		WideCharToMultiByte( CP_ACP, 0, file, -1, afile, MAX_PATH, NULL, NULL );
140 		WideCharToMultiByte( CP_ACP, 0, mode, -1, amode, 16, NULL, NULL );
141 
142 
143 		return fopen( afile, amode );
144 	}
145 	else
146 #endif
147 		return _tfopen( file, mode );
148 }
149 
150 
151 static FILE *_tmpfile(void)
152 {
153 	FILE *fp = NULL;
154 
155 	TCHAR	szTempPath[MAX_PATH];
156 
157 	if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
158 	{
159 		TCHAR	szFileName[MAX_PATH];
160 
161 		if ( GetTempFileName( szTempPath, TEXT("CRT"), 0, szFileName ) )
162 		{
163 			HANDLE	hFile =  CreateFile(
164 				szFileName,
165 				GENERIC_READ | GENERIC_WRITE,
166 				0, NULL,
167 				OPEN_EXISTING,
168 				FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_NORMAL,
169 				NULL );
170 
171 			if ( IsValidHandle( hFile ) )
172 			{
173 				int fd = _open_osfhandle( (int)hFile, 0 );
174 
175 				fp = _fdopen( fd, "w+b" );
176 			}
177 		}
178 	}
179 
180 	return fp;
181 }
182 //***************************************************************************
183 
184 static BOOL GetCrashDataPath( LPTSTR szBuffer )
185 {
186 	::rtl::OUString	ustrValue = ::rtl::OUString::createFromAscii("${$BRAND_BASE_DIR/program/bootstrap.ini:UserInstallation}");
187 	::rtl::Bootstrap::expandMacros( ustrValue );
188 
189 	if ( ustrValue.getLength() )
190 	{
191 		ustrValue += ::rtl::OUString::createFromAscii("/user/crashdata");
192 
193 		::osl::FileBase::RC	result = ::osl::Directory::createPath( ustrValue );
194 
195 		if ( ::osl::FileBase::E_None == result || ::osl::FileBase::E_EXIST == result )
196 		{
197 			::rtl::OUString	ustrPath;
198 
199 			result = ::osl::FileBase::getSystemPathFromFileURL( ustrValue, ustrPath );
200 			if (  ::osl::FileBase::E_None == result  )
201 			{
202 				_tcsncpy( szBuffer, reinterpret_cast<LPCWSTR>(ustrPath.getStr()), MAX_PATH );
203 				return TRUE;
204 			}
205 		}
206 	}
207 
208 	return FALSE;
209 }
210 
211 
212 static FILE *_open_reportfile( LPCTSTR lpExt, LPCTSTR lpMode )
213 {
214 	FILE	*fp = NULL;
215 	TCHAR	szAppDataPath[MAX_PATH] = _T("");
216 
217 	if ( GetCrashDataPath( szAppDataPath ) )
218 	{
219 		_tcscat( szAppDataPath, _T("\\crashdat") );
220 		_tcscat( szAppDataPath, lpExt );
221 
222 		fp = _xfopen( szAppDataPath, lpMode );
223 	}
224 
225 	return fp;
226 }
227 
228 //***************************************************************************
229 
230 struct CrashReportParams
231 {
232 	BOOL				fAllowContact;
233 	tstring				sEmail;
234 	tstring				sTitle;
235 	tstring				sComment;
236 	ULONG				uInternetConnection;
237 	tstring				sProxyServer;
238 	tstring				sProxyPort;
239 
240 	CrashReportParams();
241 
242 	void WriteToRegistry();
243 	void ReadFromRegistry();
244 	void ReadFromEnvironment();
245 };
246 
247 bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams );
248 BOOL WriteCommentFile( LPCTSTR lpComment );
249 
250 //***************************************************************************
251 
252 LONG RegReadValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPVOID lpData, DWORD cbData )
253 {
254 	HKEY	hKey = NULL;
255 	LONG	lResult;
256 
257 	lResult = RegOpenKeyEx( hBaseKey, lpSubKey, 0, KEY_QUERY_VALUE, &hKey );
258 
259 	if ( ERROR_SUCCESS == lResult )
260 	{
261 		lResult = RegQueryValueEx( hKey, lpValueName, NULL, NULL, (LPBYTE)lpData, &cbData );
262 		RegCloseKey( hKey );
263 	}
264 
265 	return lResult;
266 }
267 
268 //***************************************************************************
269 
270 LONG RegWriteValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData )
271 {
272 	HKEY	hKey = NULL;
273 	LONG	lResult;
274 
275 	lResult = RegCreateKeyEx( hBaseKey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL );
276 
277 	if ( ERROR_SUCCESS == lResult )
278 	{
279 		lResult = RegSetValueEx( hKey, lpValueName, NULL, dwType, (CONST BYTE *)lpData, cbData );
280 		RegCloseKey( hKey );
281 	}
282 
283 	return lResult;
284 }
285 
286 //***************************************************************************
287 
288 CrashReportParams::CrashReportParams()
289 {
290 	fAllowContact = FALSE;
291 	sTitle = TEXT("");
292 	sComment = TEXT("");
293 	sEmail = TEXT("");
294 	uInternetConnection = 0;
295 	sProxyServer = TEXT("");
296 	sProxyPort = TEXT("");
297 }
298 
299 //***************************************************************************
300 
301 void CrashReportParams::ReadFromRegistry()
302 {
303 	TCHAR	szBuffer[2048];
304 
305 	if ( ERROR_SUCCESS == RegReadValue(
306 		HKEY_CURRENT_USER,
307 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
308 		TEXT("HTTPProxyServer"),
309 		szBuffer,
310 		sizeof(szBuffer) ) )
311 		sProxyServer = szBuffer;
312 
313 	DWORD	dwProxyPort;
314 
315 	if ( ERROR_SUCCESS == RegReadValue(
316 		HKEY_CURRENT_USER,
317 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
318 		TEXT("HTTPProxyPort"),
319 		&dwProxyPort,
320 		sizeof(dwProxyPort) ) )
321 	{
322 		_stprintf( szBuffer, TEXT("%d"), dwProxyPort );
323 		sProxyPort = szBuffer;
324 	}
325 
326 	if ( ERROR_SUCCESS == RegReadValue(
327 		HKEY_CURRENT_USER,
328 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
329 		TEXT("ReturnAddress"),
330 		szBuffer,
331 		sizeof(szBuffer) ) )
332 		sEmail = szBuffer;
333 
334 	RegReadValue(
335 		HKEY_CURRENT_USER,
336 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
337 		TEXT("AllowContact"),
338 		&fAllowContact,
339 		sizeof(fAllowContact) );
340 
341 	RegReadValue(
342 		HKEY_CURRENT_USER,
343 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
344 		TEXT("HTTPConnection"),
345 		&uInternetConnection,
346 		sizeof(uInternetConnection) );
347 }
348 
349 //***************************************************************************
350 
351 void CrashReportParams::WriteToRegistry()
352 {
353 	RegWriteValue(
354 		HKEY_CURRENT_USER,
355 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
356 		TEXT("HTTPProxyServer"), REG_SZ,
357 		sProxyServer.c_str(),
358 		sizeof(TCHAR) * (sProxyServer.length() + 1) );
359 
360 	LPTSTR endptr = NULL;
361 	DWORD dwProxyPort = _tcstoul( sProxyPort.c_str(), &endptr, 10 );
362 
363 	RegWriteValue(
364 		HKEY_CURRENT_USER,
365 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
366 		TEXT("HTTPProxyPort"), REG_DWORD,
367 		&dwProxyPort,
368 		sizeof(DWORD) );
369 
370 	RegWriteValue(
371 		HKEY_CURRENT_USER,
372 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
373 		TEXT("AllowContact"), REG_DWORD,
374 		&fAllowContact,
375 		sizeof(DWORD) );
376 
377 
378 	RegWriteValue(
379 		HKEY_CURRENT_USER,
380 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
381 		TEXT("HTTPConnection"), REG_DWORD,
382 		&uInternetConnection,
383 		sizeof(DWORD) );
384 
385 	RegWriteValue(
386 		HKEY_CURRENT_USER,
387 		TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"),
388 		TEXT("ReturnAddress"), REG_SZ,
389 		sEmail.c_str(),
390 		sizeof(TCHAR) * (sEmail.length() + 1) );
391 }
392 
393 //***************************************************************************
394 
395 void CrashReportParams::ReadFromEnvironment()
396 {
397 	TCHAR	szBuffer[2048];
398 
399 	DWORD dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPPROXYSERVER"), szBuffer, elementsof(szBuffer) );
400 
401 	if ( dwResult && dwResult < elementsof(szBuffer) )
402 		sProxyServer = szBuffer;
403 
404 	dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPPROXYPORT"), szBuffer, elementsof(szBuffer) );
405 
406 	if ( dwResult && dwResult < elementsof(szBuffer) )
407 		sProxyPort = szBuffer;
408 
409 	dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_RETURNADDRESS"), szBuffer, elementsof(szBuffer) );
410 
411 	if ( dwResult && dwResult < elementsof(szBuffer) )
412 	{
413 		sEmail = szBuffer;
414 		// fAllowContact = TRUE;
415 	}
416 
417 	dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPCONNECTIONTYPE"), szBuffer, elementsof(szBuffer) );
418 
419 	if ( dwResult && dwResult < elementsof(szBuffer) )
420 	{
421 		if ( 0 == _tcsicmp( szBuffer, _T("DIRECT") ) )
422 			uInternetConnection = 1;
423 		else if ( 0 == _tcsicmp( szBuffer, _T("MANUALPROXY") ) )
424 			uInternetConnection = 2;
425 		else if ( 0 == _tcsicmp( szBuffer, _T("SYSTEMDEFAULT") ) )
426 			uInternetConnection = 0;
427 	}
428 
429 	dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_SUBJECT"), szBuffer, elementsof(szBuffer) );
430 
431 	if ( dwResult && dwResult < elementsof(szBuffer) )
432 		sTitle = szBuffer;
433 
434 
435 	dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_BODYFILE"), szBuffer, elementsof(szBuffer) );
436 
437 	if ( dwResult && dwResult < elementsof(szBuffer) )
438 	{
439 		FILE *fp = _xfopen( szBuffer, _T("rb") );
440 
441 		if ( fp )
442 		{
443 			CHAR	aUTF8Buffer[256];
444 			size_t	nBytesRead;
445 
446 			sComment = TEXT("");
447 
448 			while ( 0 != (nBytesRead = fread( aUTF8Buffer, sizeof(aUTF8Buffer[0]), elementsof(aUTF8Buffer), fp )) )
449 			{
450 				TCHAR	aBuffer[256+1];
451 
452 				DWORD	dwCharacters = MultiByteToWideChar( CP_UTF8, 0, aUTF8Buffer, nBytesRead, aBuffer, elementsof(aBuffer) - 1 );
453 				aBuffer[dwCharacters] = 0;
454 				sComment += aBuffer;
455 			}
456 
457 			fclose( fp );
458 		}
459 	}
460 }
461 
462 //***************************************************************************
463 
464 typedef BOOL (WINAPI *MiniDumpWriteDump_PROC)(
465     IN HANDLE hProcess,
466     IN DWORD ProcessId,
467     IN HANDLE hFile,
468     IN MINIDUMP_TYPE DumpType,
469     IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
470     IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
471     IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
472     );
473 
474 //***************************************************************************
475 
476 static BOOL WINAPI InitRichEdit()
477 {
478 	return (NULL != LoadLibrary( RICHEDIT ));
479 }
480 
481 //***************************************************************************
482 
483 static BOOL WINAPI DeinitRichEdit()
484 {
485 	return FreeLibrary( GetModuleHandle( RICHEDIT ) );
486 }
487 
488 //***************************************************************************
489 
490 static string trim_string( const string& rString )
491 {
492 	string temp = rString;
493 
494 	while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' )
495 		temp.erase( 0, 1 );
496 
497 	string::size_type	len = temp.length();
498 
499 	while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' )
500 	{
501 		temp.erase( len - 1, 1 );
502 		len = temp.length();
503 	}
504 
505 	return temp;
506 }
507 
508 //***************************************************************************
509 
510 static int LoadAndFormatString( HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax )
511 {
512 	TCHAR	szBuffer[FORMATBUFSIZE];
513 	TCHAR	szBuffer2[FORMATBUFSIZE];
514 
515 	LoadString( hInstance, uID, szBuffer, elementsof(szBuffer) );
516 
517 	LPCTSTR	src;
518 	LPTSTR	dest;
519 	for ( dest = szBuffer2, src = szBuffer; *src; src++, dest++ )
520 	{
521 		switch ( *src )
522 		{
523 		case '~':
524 			*dest = '&';
525 			break;
526 		case '\\':
527 			switch ( *(++src) )
528 			{
529 			case 'n':
530 				*dest = '\n';
531 				break;
532 			case 'r':
533 				*dest = '\r';
534 				break;
535 			default:
536 				*dest = *src;
537 				break;
538 			}
539 			break;
540 		default:
541 			*dest = *src;
542 			break;
543 		}
544 	}
545 
546 	*dest = *src;
547 
548 	return ExpandEnvironmentStrings( szBuffer2, lpBuffer, nBufferMax );
549 }
550 
551 
552 //***************************************************************************
553 
554 static string wstring2utf8( const wstring &rString )
555 {
556 	int nBufSize = WideCharToMultiByte( CP_UTF8, 0, rString.c_str(), -1, NULL, 0, NULL, FALSE );
557 
558 	LPSTR	pBuffer = (LPSTR)alloca( nBufSize );
559 
560 	WideCharToMultiByte(  CP_UTF8, 0, rString.c_str(), -1, pBuffer, nBufSize, NULL, FALSE );
561 
562 	return string( pBuffer );
563 }
564 
565 //***************************************************************************
566 
567 static string xml_encode( const string &rString )
568 {
569 	string temp = rString;
570     string::size_type pos = 0;
571 
572 	// First replace all occurences of '&' because it may occur in further
573 	// encoded chardters too
574 
575     for( pos = 0; (pos = temp.find( '&', pos )) != string::npos; pos += 4 )
576         temp.replace( pos, 1, "&amp;" );
577 
578 	for( pos = 0; (pos = temp.find( '<', pos )) != string::npos; pos += 4 )
579         temp.replace( pos, 1, "&lt;" );
580 
581     for( pos = 0; (pos = temp.find( '>', pos )) != string::npos; pos += 4 )
582         temp.replace( pos, 1, "&gt;" );
583 
584 	return temp;
585 }
586 
587 //***************************************************************************
588 
589 static size_t fcopy( FILE *fpin, FILE *fpout )
590 {
591 	char buffer[1024];
592 	size_t nBytes;
593 	size_t nBytesWritten = 0;
594 
595 	if ( fpin && fpout )
596 	{
597 		while ( 0 != (nBytes = fread( buffer, 1, sizeof(buffer), fpin )) )
598 		{
599 			nBytesWritten += fwrite( buffer, 1, nBytes, fpout );
600 		}
601 	}
602 
603 	return nBytesWritten;
604 }
605 
606 //***************************************************************************
607 
608 static string GetModuleDirectory( HMODULE hModule )
609 {
610 	TCHAR	szModuleName[MAX_PATH] = TEXT("");
611 	TCHAR	szDrive[_MAX_DRIVE];
612 	TCHAR	szDir[_MAX_DIR];
613 	TCHAR	szFName[_MAX_FNAME];
614 	TCHAR	szExt[_MAX_EXT];
615 
616 	if ( GetModuleFileName( hModule, szModuleName, MAX_PATH ) )
617 	{
618 		_tsplitpath( szModuleName, szDrive, szDir, szFName, szExt );
619 		_tmakepath( szModuleName, szDrive, szDir, _T(""), _T("") );
620 	}
621 
622 	CHAR	szModuleNameUTF8[MAX_PATH] = "";
623 
624 	WideCharToMultiByte( CP_UTF8, 0, szModuleName, -1, szModuleNameUTF8, elementsof(szModuleNameUTF8), NULL, NULL );
625 	return string( szModuleNameUTF8 );
626 }
627 
628 //***************************************************************************
629 
630 string GetFileDirectory( const string& rFilePath )
631 {
632 	string aDir = rFilePath;
633     size_t pos = aDir.rfind( '\\' );
634 
635 	if ( string::npos != pos )
636 		aDir.erase( pos + 1 );
637 	else
638 		aDir = "";
639 
640 	return aDir;
641 }
642 
643 //***************************************************************************
644 
645 string GetFileName( const string& rFilePath )
646 {
647 	string aName = rFilePath;
648     size_t pos = aName.rfind( '\\' );
649 
650 	if ( string::npos != pos )
651 		return aName.substr( pos + 1 );
652 	else
653 		return aName;
654 }
655 
656 //***************************************************************************
657 
658 BOOL WriteReportFile( CrashReportParams *pParams )
659 {
660 	BOOL	fSuccess = FALSE;
661 	TCHAR	szTempPath[MAX_PATH];
662 
663 	if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
664 	{
665 		TCHAR	szFileName[MAX_PATH];
666 
667 		if ( GetTempFileName( szTempPath, TEXT("RPM"), 0, szFileName ) )
668 		{
669 			HANDLE	hFile =  CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
670 
671 			if ( hFile )
672 			{
673 				int	fd = _open_osfhandle( (LONG)hFile, _O_TEXT );
674 				FILE	*fp = _fdopen( fd, "w+t" );
675 				CHAR	szTitle[1024] = "";
676 				CHAR	szBuildId[1024] = "";
677 				CHAR	szEmail[1024] = "";
678 				const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
679 
680 				WideCharToMultiByte( CP_UTF8, 0, pParams->sTitle.c_str(), -1, szTitle, sizeof(szTitle), NULL, NULL );
681 				WideCharToMultiByte( CP_UTF8, 0, g_szBuildId, -1, szBuildId, sizeof(szBuildId), NULL, NULL );
682 				WideCharToMultiByte( CP_UTF8, 0, pParams->sEmail.c_str(), -1, szEmail, sizeof(szEmail), NULL, NULL );
683 
684 				fprintf( fp,
685 					"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
686 					"<!DOCTYPE errormail:errormail PUBLIC \"-//OpenOffice.org//DTD ErrorMail 1.0//EN\" \"errormail.dtd\">\n"
687 					"<errormail:errormail xmlns:errormail=\"http://openoffice.org/2002/errormail\" usertype=\"%s\">\n"
688 					"<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.1\" feedback=\"%s\" email=\"%s\">\n",
689 					pszUserType ? pszUserType : "",
690 					pParams->fAllowContact ? "true" : "false",
691 					pParams->fAllowContact ? xml_encode(szEmail).c_str() : ""
692 					);
693 
694 				fprintf( fp,
695 					"<reportmail:title>%s</reportmail:title>\n",
696 					xml_encode(szTitle).c_str() );
697 
698 				fprintf( fp,
699 					"<reportmail:attachment name=\"description.txt\" media-type=\"text/plain;charset=UTF-8\" class=\"UserComment\"/>\n"
700 					"<reportmail:attachment name=\"user.dmp\" media-type=\"application/octet-stream\" class=\"UserDump\"/>\n"
701 					"</reportmail:mail>\n"
702 
703 					"<officeinfo:officeinfo xmlns:officeinfo=\"http://openoffice.org/2002/officeinfo\" build=\"%s\" platform=\"%s\" language=\"%s\" procpath=\"%s\" exceptiontype=\"0x%08X\" product=\"%s\"/>\n",
704 					szBuildId,
705 					_INPATH,
706 					xml_encode(g_strDefaultLanguage).c_str(),
707 					xml_encode(GetModuleDirectory( NULL )).c_str(),
708 					g_dwExceptionCode,
709 					xml_encode(wstring2utf8(g_wstrProductKey)).c_str()
710 					);
711 
712 				OSVERSIONINFO	VersionInfo;
713 
714 				ZeroMemory( &VersionInfo, sizeof(VersionInfo) );
715 				VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo );
716 
717 				GetVersionEx( &VersionInfo );
718 
719 				fprintf( fp,
720 					"<systeminfo:systeminfo xmlns:systeminfo=\"http://openoffice.org/2002/systeminfo\">\n"
721 					"<systeminfo:System name=\"%s\" version=\"%d.%d\" build=\"%d\" locale=\"0x%08x\"/>\n"
722 					,
723 					VER_PLATFORM_WIN32_NT == VersionInfo.dwPlatformId ? "Windows NT" : "Windows",
724 					VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion,
725 					VersionInfo.dwBuildNumber,
726 					GetUserDefaultLangID()
727 
728 					);
729 				fprintf( fp, "<systeminfo:CPU type=\"x86\"/>\n" );
730 				fprintf( fp, "</systeminfo:systeminfo>\n" );
731 
732 				fseek( g_fpStackFile, 0, SEEK_SET );
733 				fcopy( g_fpStackFile, fp );
734 
735 				fseek( g_fpChecksumFile, 0, SEEK_SET );
736 				fcopy( g_fpChecksumFile, fp );
737 
738 				fprintf( fp, "</errormail:errormail>\n" );
739 
740 				fclose( fp );
741 
742 				fSuccess = TRUE;
743 
744 				WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szReportFileNameA, MAX_PATH, NULL, NULL );
745 			}
746 
747 			if ( !fSuccess )
748 				DeleteFile( szFileName );
749 		}
750 	}
751 
752 	return fSuccess;
753 }
754 
755 //***************************************************************************
756 
757 static BOOL SaveDumpFile( HWND hwndOwner )
758 {
759 	OPENFILENAME	ofn;
760 	TCHAR	szFileName[MAX_PATH] = TEXT("");
761 
762 	ZeroMemory( &ofn, sizeof(ofn) );
763 	ofn.lStructSize = sizeof(ofn);
764 
765 	ofn.hwndOwner = hwndOwner;
766 	ofn.lpstrFilter = TEXT("*.dmp\0*.dmp\0*.*\0*.*\0");
767 	ofn.lpstrFile = szFileName;
768 	ofn.nMaxFile = MAX_PATH;
769 	ofn.Flags = OFN_ENABLESIZING | OFN_LONGNAMES | OFN_OVERWRITEPROMPT;
770 	ofn.lpstrDefExt = TEXT("dmp");
771 
772 	if ( GetSaveFileName( &ofn ) )
773 	{
774 		return CopyFile( g_szDumpFileName, szFileName, FALSE );
775 	}
776 
777 
778 	return FALSE;
779 }
780 
781 //***************************************************************************
782 
783 static BOOL ScreenToClientRect( HWND hwnd, LPRECT lprc )
784 {
785 	return ScreenToClient( hwnd, (LPPOINT)&lprc->left ) && ScreenToClient( hwnd, (LPPOINT)&lprc->right );
786 }
787 
788 static BOOL SetWindowRect( HWND hwnd, const RECT *lprc, BOOL fRepaint )
789 {
790 	return MoveWindow( hwnd, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, fRepaint );
791 }
792 
793 #define GM_LOX	0x01
794 #define GM_HIX	0x02
795 #define GM_LOY	0x04
796 #define GM_HIY	0x08
797 
798 static BOOL SetGrowMode( HWND hwnd, DWORD dwGrowMode )
799 {
800 	return SetProp( hwnd, TEXT("GrowMode"), (HANDLE)dwGrowMode );
801 }
802 
803 static DWORD GetGrowMode( HWND hwnd )
804 {
805 	return (DWORD)GetProp( hwnd, TEXT("GrowMode") );
806 }
807 
808 static BOOL GrowWindow( HWND hwnd, LONG dxClient, LONG dyClient, BOOL fRepaint )
809 {
810 	DWORD	dwGrowMode = GetGrowMode( hwnd );
811 	RECT	rc;
812 
813 	GetWindowRect( hwnd, &rc );
814 
815 	if ( dwGrowMode & GM_LOX )
816 		rc.left += dxClient;
817 	if ( dwGrowMode & GM_HIX )
818 		rc.right += dxClient;
819 	if ( dwGrowMode & GM_LOY )
820 		rc.top += dyClient;
821 	if ( dwGrowMode & GM_HIY )
822 		rc.bottom += dyClient;
823 
824 	ScreenToClientRect( GetParent( hwnd ), &rc );
825 	SetWindowRect( hwnd, &rc, fRepaint );
826 
827 	return TRUE;
828 }
829 
830 BOOL CALLBACK GrowChildWindows(
831   HWND hwnd,      // handle to child window
832   LPARAM lParam   // application-defined value
833 )
834 {
835 	LONG	cx = (SHORT)LOWORD( lParam );
836 	LONG	cy = (SHORT)HIWORD( lParam );
837 
838 	GrowWindow( hwnd, cx, cy, TRUE );
839 
840 	return TRUE;
841 }
842 
843 /*
844 BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
845 {
846     HFONT aFont = *((HFONT*) lParam);
847     HDC hDC = GetDC( hwndChild );
848     SelectObject( hDC, aFont );
849     ReleaseDC( hwndChild, hDC );
850     return TRUE;
851 }
852 
853 void ApplySystemFont( HWND hwndDlg )
854 {
855     NONCLIENTMETRICSA aNonClientMetrics;
856     aNonClientMetrics.cbSize = sizeof( aNonClientMetrics );
857     if ( SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) )
858     {
859         HFONT aSysFont = CreateFontIndirectA( &aNonClientMetrics.lfMessageFont );
860         EnumChildWindows(hwndDlg, EnumChildProc, (LPARAM) &aSysFont);
861     }
862 }
863 */
864 
865 BOOL CALLBACK PreviewDialogProc(
866 	HWND hwndDlg,
867 	UINT uMsg,
868 	WPARAM wParam,
869 	LPARAM lParam
870 	)
871 {
872 	static RECT	rcClient;
873 
874 	switch ( uMsg )
875 	{
876 	case WM_SIZE:
877 		{
878 		LONG	cx = LOWORD( lParam );
879 		LONG	cy = HIWORD( lParam );
880 		LONG	dxClient, dyClient;
881 
882 		dxClient = cx - rcClient.right;
883 		dyClient = cy - rcClient.bottom;
884 
885 		EnumChildWindows( hwndDlg, GrowChildWindows, MAKELONG( (SHORT)dxClient, (SHORT)dyClient) );
886 
887 		GetClientRect( hwndDlg, &rcClient );
888 		}
889 		break;
890 	case WM_INITDIALOG:
891 		{
892 			GetClientRect( hwndDlg, &rcClient );
893 			SetGrowMode( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GM_HIX | GM_HIY );
894 			SetGrowMode( GetDlgItem(hwndDlg, IDOK), GM_LOX | GM_HIX | GM_LOY | GM_HIY );
895 
896 			CrashReportParams *pParams = (CrashReportParams *)lParam;
897 
898 			TCHAR	szBuffer[256] = TEXT("");
899 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE );
900 			HWND	hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT );
901 
902 			GetWindowText( hwndParent, szBuffer, elementsof(szBuffer) );
903 			SetWindowText( hwndDlg, szBuffer );
904 
905 			LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) );
906 			Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer );
907 
908 			basic_string<TCHAR>	aString;
909 
910 			aString.append( pParams->sTitle );
911 			aString.append( _T("\r\n\r\n") );
912 			aString.append( pParams->sComment );
913 			aString.append( _T("\r\n---------- report ----------\r\n") );
914 
915 			FILE	*fp = fopen( g_szReportFileNameA, "r" );
916 
917 			if ( fp )
918 			{
919 				char	buf[1024];
920 
921 				while ( fgets( buf, elementsof(buf), fp ) != NULL )
922 				{
923 					WCHAR	bufW[1024];
924 
925 					MultiByteToWideChar( CP_UTF8, 0, buf, -1, bufW, elementsof(bufW) );
926 
927 					aString.append( bufW );
928 				}
929 
930 				fclose( fp );
931 			}
932 
933 			aString.append( _T("\r\n---------- stack ----------\r\n") );
934 
935 			fp = fopen( g_szDumpFileNameA, "rb" );
936 
937 			if ( fp )
938 			{
939 				unsigned char	buf[16];
940 				int		count;
941 
942 				do
943 				{
944 					int i;
945 
946 					count = fread( buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), fp );
947 
948 					for ( i = 0; i < count; i++ )
949 					{
950 						TCHAR	output[16];
951 
952 						_sntprintf( output, elementsof(output), _T("%02X\x20"), buf[i] );
953 						aString.append( output );
954 					}
955 					for ( ; i < elementsof(buf); i++ )
956 					{
957 						aString.append( _T("\x20\x20\x20") );
958 					}
959 
960 					for ( i = 0; i < count; i++ )
961 					{
962 						TCHAR	output[2];
963 
964 						if ( (int)buf[i] >= 0x20 && (int)buf[i] <= 0x7F )
965 							output[0] = (TCHAR)buf[i];
966 						else
967 							output[0] = '.';
968 						output[1] = 0;
969 						aString.append( output );
970 					}
971 
972 					aString.append( _T("\r\n") );
973 
974 				} while ( count );
975 
976 				fclose( fp );
977 			}
978 
979 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), aString.c_str() );
980 
981 
982 			SetWindowFont( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GetStockObject( SYSTEM_FIXED_FONT ), TRUE );
983 		}
984 		return TRUE;
985 	case WM_COMMAND:
986 		switch ( LOWORD(wParam) )
987 		{
988 		case IDOK:
989 		case IDCANCEL:
990 			EndDialog( hwndDlg, wParam );
991 			return TRUE;
992 		}
993 		break;
994 	default:
995 		break;
996 	}
997 
998 	return FALSE;
999 }
1000 //***************************************************************************
1001 
1002 static void PreviewReport( HWND hwndParent, CrashReportParams *pParams )
1003 {
1004 	HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndParent, GWL_HINSTANCE );
1005 
1006 	WriteReportFile( pParams );
1007 
1008 	DialogBoxParam(
1009 		hInstance,
1010 		MAKEINTRESOURCE(IDD_PREVIEW_FRAME),
1011 		hwndParent,
1012 		PreviewDialogProc,
1013 		(LPARAM)pParams
1014 		);
1015 
1016 	DeleteFileA( g_szReportFileNameA );
1017 }
1018 //***************************************************************************
1019 void UpdateOptionsDialogControls( HWND hwndDlg )
1020 {
1021 	if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED )
1022 	{
1023 		EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), TRUE );
1024 		EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), TRUE );
1025 	}
1026 	else
1027 	{
1028 		EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), FALSE );
1029 		EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), FALSE );
1030 	}
1031 }
1032 
1033 //***************************************************************************
1034 
1035 BOOL CALLBACK OptionsDialogProc(
1036 	HWND hwndDlg,
1037 	UINT uMsg,
1038 	WPARAM wParam,
1039 	LPARAM lParam
1040 	)
1041 {
1042 	static CrashReportParams *pParams;
1043 
1044 	switch ( uMsg )
1045 	{
1046 	case WM_INITDIALOG:
1047 		{
1048 			TCHAR	szBuffer[1024] = TEXT("");
1049 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE );
1050 			//HWND	hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT );
1051 
1052 			pParams = (CrashReportParams *)lParam;
1053 
1054 			LoadAndFormatString( hInstance, IDS_OPTIONS_CAPTION, szBuffer, elementsof(szBuffer) );
1055 			SetWindowText( hwndDlg, szBuffer );
1056 
1057 			LoadAndFormatString( hInstance, IDS_PROXY_SETTINGS_HEADER, szBuffer, elementsof(szBuffer) );
1058 			Static_SetText( GetDlgItem(hwndDlg, IDC_PROXY_SETTINGS), szBuffer );
1059 
1060 			LoadAndFormatString( hInstance, IDS_PROXY_SYSTEM, szBuffer, elementsof(szBuffer) );
1061 			Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM), szBuffer );
1062 
1063 			LoadAndFormatString( hInstance, IDS_PROXY_DIRECT, szBuffer, elementsof(szBuffer) );
1064 			Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT), szBuffer );
1065 
1066 			LoadAndFormatString( hInstance, IDS_PROXY_MANUAL, szBuffer, elementsof(szBuffer) );
1067 			Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL), szBuffer );
1068 
1069 			LoadAndFormatString( hInstance, IDS_LABEL_PROXYSERVER, szBuffer, elementsof(szBuffer) );
1070 			Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYSERVER), szBuffer );
1071 
1072 			LoadAndFormatString( hInstance, IDS_LABEL_PROXYPORT, szBuffer, elementsof(szBuffer) );
1073 			Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYPORT), szBuffer );
1074 
1075 			LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) );
1076 			Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer );
1077 
1078 			LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
1079 			Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
1080 
1081 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), pParams->sProxyServer.c_str() );
1082 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), pParams->sProxyPort.c_str() );
1083 
1084 			Button_SetCheck( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM + pParams->uInternetConnection), BST_CHECKED );
1085 
1086 			SendMessage(
1087 				GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION),
1088 				EM_SETBKGNDCOLOR,
1089 				(WPARAM)FALSE,
1090 				GetSysColor( COLOR_3DFACE ) );
1091 			LoadAndFormatString( hInstance, IDS_PROXY_DESCRIPTION, szBuffer, elementsof(szBuffer) );
1092 			Edit_SetText( GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION), szBuffer );
1093 
1094 			UpdateOptionsDialogControls( hwndDlg );
1095 		}
1096 		return TRUE;
1097 	case WM_COMMAND:
1098 		switch ( LOWORD(wParam) )
1099 		{
1100 		case IDC_RADIO_SYSTEM:
1101 		case IDC_RADIO_DIRECT:
1102 		case IDC_RADIO_MANUAL:
1103 			if ( BN_CLICKED == HIWORD(wParam) )
1104 				UpdateOptionsDialogControls( hwndDlg );
1105 			break;
1106 		case IDOK:
1107 			{
1108 			TCHAR szBuffer[1024];
1109 
1110 			Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), szBuffer, elementsof(szBuffer) );
1111 			pParams->sProxyServer = szBuffer;
1112 
1113 			Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), szBuffer, elementsof(szBuffer) );
1114 			pParams->sProxyPort = szBuffer;
1115 
1116 			if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT) ) & BST_CHECKED )
1117 				pParams->uInternetConnection = 1;
1118 			else if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED )
1119 				pParams->uInternetConnection = 2;
1120 			else
1121 				pParams->uInternetConnection = 0;
1122 			}
1123 		case IDCANCEL:
1124 			EndDialog( hwndDlg, wParam );
1125 			return TRUE;
1126 		}
1127 		break;
1128 	default:
1129 		break;
1130 	}
1131 
1132 	return FALSE;
1133 }
1134 
1135 //***************************************************************************
1136 
1137 static void OptionsDialog( HWND hwndParent, CrashReportParams *pParams )
1138 {
1139 	HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndParent, GWL_HINSTANCE );
1140 
1141 	if ( IDOK == DialogBoxParam(
1142 		hInstance,
1143 		MAKEINTRESOURCE(IDD_OPTIONS_FRAME),
1144 		hwndParent,
1145 		OptionsDialogProc,
1146 		(LPARAM)pParams
1147 		) )
1148 		pParams->WriteToRegistry();
1149 
1150 }
1151 //***************************************************************************
1152 
1153 void UpdateReportDialogControls( HWND hwndDlg )
1154 {
1155 	EnableWindow(
1156 		GetDlgItem(hwndDlg, IDC_EDIT_EMAIL),
1157 		Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT)) & BST_CHECKED ? TRUE : FALSE );
1158 	EnableWindow(
1159 		GetDlgItem(hwndDlg, IDC_LABEL_EMAIL),
1160 		Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT)) & BST_CHECKED ? TRUE : FALSE );
1161 }
1162 
1163 //***************************************************************************
1164 
1165 BOOL CALLBACK ReportDialogProc(
1166 	HWND hwndDlg,
1167 	UINT uMsg,
1168 	WPARAM wParam,
1169 	LPARAM
1170 	)
1171 {
1172 	switch ( uMsg )
1173 	{
1174 	case WM_INITDIALOG:
1175 		{
1176 		    CrashReportParams	*pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
1177 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
1178 			TCHAR		szBuffer[FORMATBUFSIZE];
1179 
1180 			LoadAndFormatString( hInstance, IDS_REPORT_INTRO, szBuffer, elementsof(szBuffer) );
1181 			Static_SetText( GetDlgItem(hwndDlg, IDC_REPORT_INTRO), szBuffer );
1182 
1183 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT3), szBuffer );
1184 
1185 			LoadAndFormatString( hInstance, IDS_ENTER_TITLE, szBuffer, elementsof(szBuffer) );
1186 			Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_TITLE), szBuffer );
1187 
1188 			LoadAndFormatString( hInstance, IDS_ENTER_DESCRIPTION, szBuffer, elementsof(szBuffer) );
1189 			Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_DESCRIPTION), szBuffer );
1190 
1191 			LoadAndFormatString( hInstance, IDS_SHOW_REPORT_BUTTON, szBuffer, elementsof(szBuffer) );
1192 			Button_SetText( GetDlgItem(hwndDlg, IDC_SHOW_REPORT), szBuffer );
1193 
1194 			LoadAndFormatString( hInstance, IDS_SAVE_REPORT_BUTTON, szBuffer, elementsof(szBuffer) );
1195 			Button_SetText( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), szBuffer );
1196 
1197 			const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
1198 			if ( pszUserType )
1199 				ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_SHOW );
1200 			else
1201 				ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_HIDE );
1202 
1203 			LoadAndFormatString( hInstance, IDS_OPTIONS_BUTTON, szBuffer, elementsof(szBuffer) );
1204 			Button_SetText( GetDlgItem(hwndDlg, IDC_OPTIONS), szBuffer );
1205 
1206 			LoadAndFormatString( hInstance, IDS_ALLOW_CONTACT, szBuffer, elementsof(szBuffer) );
1207 			Button_SetText( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), szBuffer );
1208 			Button_SetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), pParams->fAllowContact ? BST_CHECKED : BST_UNCHECKED );
1209 
1210 			LoadAndFormatString( hInstance, IDS_LABEL_EMAIL, szBuffer, elementsof(szBuffer) );
1211 			Button_SetText( GetDlgItem(hwndDlg, IDC_LABEL_EMAIL), szBuffer );
1212 
1213 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), pParams->sEmail.c_str() );
1214 
1215 			UpdateReportDialogControls( hwndDlg );
1216 		}
1217 		return TRUE;
1218 	case WM_SHOWWINDOW:
1219 		if ( (BOOL)wParam )
1220 		{
1221 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
1222 			CrashReportParams	*pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
1223 			TCHAR		szBuffer[FORMATBUFSIZE];
1224 
1225 			LoadAndFormatString( hInstance, IDS_REPORT_CAPTION, szBuffer, elementsof(szBuffer) );
1226 			SetWindowText( GetParent(hwndDlg), szBuffer );
1227 
1228 			LoadAndFormatString( hInstance, IDS_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
1229 			SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer );
1230 
1231 			LoadAndFormatString( hInstance, IDS_DONOT_SEND_BUTTON, szBuffer, elementsof(szBuffer) );
1232 			Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer );
1233 
1234 
1235 			ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), TRUE );
1236 			ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), TRUE );
1237 			ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), FALSE );
1238 
1239 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), pParams->sTitle.c_str() );
1240 			Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), pParams->sComment.c_str() );
1241 
1242             /*
1243 			SetWindowLong( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWL_STYLE,
1244                 GetWindowLong( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWL_STYLE) | BS_DEFPUSHBUTTON );
1245 			SetWindowLong( GetDlgItem(GetParent(hwndDlg),IDBACK), GWL_STYLE,
1246                 GetWindowLong( GetDlgItem(GetParent(hwndDlg),IDBACK), GWL_STYLE) &~ BS_DEFPUSHBUTTON );
1247                 */
1248 			SetFocus( GetDlgItem(hwndDlg,IDC_EDIT_TITLE) );
1249 		}
1250 		break;
1251 	case WM_COMMAND:
1252 		switch ( LOWORD(wParam) )
1253 		{
1254 		case IDC_SHOW_REPORT:
1255 			{
1256 				TCHAR	szBuffer[32767];
1257 
1258 				CrashReportParams	*pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
1259 
1260 				pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT) ) ? TRUE : FALSE;
1261 
1262 				Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) );
1263 				pParams->sTitle = szBuffer;
1264 
1265 				Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) );
1266 				pParams->sComment = szBuffer;
1267 
1268 				Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) );
1269 				pParams->sEmail = szBuffer;
1270 
1271 				PreviewReport( GetParent(hwndDlg), pParams );
1272 			}
1273 			return TRUE;
1274 		case IDC_SAVE_REPORT:
1275 			SaveDumpFile( GetParent(hwndDlg) );
1276 			return TRUE;
1277 		case IDC_OPTIONS:
1278 			{
1279 				CrashReportParams	*pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA );
1280 				OptionsDialog( GetParent(hwndDlg), pParams );
1281 			}
1282 			return TRUE;
1283 		case IDC_ALLOW_CONTACT:
1284 			if ( BN_CLICKED == HIWORD(wParam) )
1285 				UpdateReportDialogControls( hwndDlg );
1286 			return TRUE;
1287 		}
1288 		break;
1289 	default:
1290 		break;
1291 	}
1292 
1293 	return FALSE;
1294 }
1295 //***************************************************************************
1296 
1297 BOOL CALLBACK WelcomeDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
1298 {
1299 	switch ( uMsg )
1300 	{
1301 	case WM_INITDIALOG:
1302 		{
1303 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
1304 			HWND	hwndRichEdit = GetDlgItem(hwndDlg, IDC_RICHEDIT21);
1305 			TCHAR	szBuffer[FORMATBUFSIZE];
1306 			TCHAR	szBuffer2[FORMATBUFSIZE];
1307 			TCHAR	szURL[256];
1308 			TCHAR	szCaption[256];
1309 
1310 			SendMessage(
1311 				hwndRichEdit,
1312 				EM_SETBKGNDCOLOR,
1313 				(WPARAM)FALSE,
1314 				GetSysColor( COLOR_3DFACE ) );
1315 
1316 			SendMessage( hwndRichEdit, EM_SETEVENTMASK, 0, ENM_LINK );
1317 			SendMessage( hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0 );
1318 
1319 			LoadAndFormatString( hInstance, IDS_WELCOME_BODY1, szBuffer, elementsof(szBuffer) );
1320 			LoadAndFormatString( hInstance, IDS_WELCOME_BODY2, szBuffer2, elementsof(szBuffer2) );
1321 			_tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) );
1322 			LoadAndFormatString( hInstance, IDS_WELCOME_BODY3, szBuffer2, elementsof(szBuffer2) );
1323 			_tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) );
1324 			LoadString( hInstance, IDS_PRIVACY_URL, szURL, elementsof(szURL) );
1325 			_tcsncat( szBuffer, szURL, elementsof(szBuffer) );
1326 			SetWindowText( hwndRichEdit, szBuffer );
1327 
1328 			LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szCaption, elementsof(szCaption) );
1329 			SetWindowText( GetParent(hwndDlg), szCaption );
1330 
1331 		}
1332 		return TRUE;
1333 	case WM_SHOWWINDOW:
1334 		if ( (BOOL)wParam )
1335 		{
1336 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
1337 			TCHAR		szBuffer[FORMATBUFSIZE];
1338 
1339 			LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szBuffer, elementsof(szBuffer) );
1340 			SetWindowText( GetParent(hwndDlg), szBuffer );
1341 
1342 			LoadAndFormatString( hInstance, IDS_WELCOME_HEADER, szBuffer, elementsof(szBuffer) );
1343 			SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer );
1344 
1345 			LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
1346 			Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer );
1347 
1348 			ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), FALSE );
1349 			ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), FALSE );
1350 			ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), TRUE );
1351 
1352 			SetFocus( GetDlgItem(GetParent(hwndDlg),IDNEXT) );
1353 		}
1354 		break;
1355 	case WM_NOTIFY:
1356 		{
1357 			LPNMHDR	pnmh = (LPNMHDR)lParam;
1358 
1359 			if ( pnmh->idFrom == IDC_RICHEDIT21 && pnmh->code == EN_LINK )
1360 			{
1361 				ENLINK	*plink = (ENLINK*)lParam;
1362 
1363 				if ( plink->msg == WM_LBUTTONUP )
1364 				{
1365 					TCHAR	szBuffer[256];
1366 					TEXTRANGE	range;
1367 
1368 					range.chrg = plink->chrg;
1369 					range.lpstrText = szBuffer;
1370 
1371 					SendMessage( pnmh->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&range );
1372 
1373 					ShellExecute( hwndDlg, NULL, szBuffer, NULL, NULL, SW_SHOWDEFAULT );
1374 				}
1375 
1376 			}
1377 		}
1378 		break;
1379 	default:
1380 		break;
1381 	}
1382 
1383 	return FALSE;
1384 }
1385 //***************************************************************************
1386 
1387 BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
1388 {
1389 	static	HWND	hwndPages[2] = { NULL };
1390 	static	int		iActualPage = 0;
1391 
1392 	switch ( uMsg )
1393 	{
1394 	case WM_INITDIALOG:
1395 		{
1396 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE );
1397 			TCHAR		szBuffer[FORMATBUFSIZE];
1398 
1399 			SetWindowLong( hwndDlg, GWL_USERDATA, (LONG)lParam );
1400 			hwndPages[0] = CreateDialog(
1401 				hInstance,
1402 				MAKEINTRESOURCE(IDD_WELCOME_PAGE),
1403 				hwndDlg,
1404 				WelcomeDialogProc );
1405 
1406 			hwndPages[1] = CreateDialog(
1407 				hInstance,
1408 				MAKEINTRESOURCE(IDD_REPORT_PAGE),
1409 				hwndDlg,
1410 				ReportDialogProc );
1411 
1412 			CHARFORMAT	chfmt;
1413 
1414 			chfmt.cbSize = sizeof(chfmt);
1415 			chfmt.dwMask = CFM_BOLD;
1416 			chfmt.dwEffects = CFE_BOLD;
1417 
1418 			SendMessage(
1419 				GetDlgItem(hwndDlg, IDC_HEADER),
1420 				EM_SETCHARFORMAT,
1421 				SCF_ALL,
1422 				(LPARAM)&chfmt );
1423 
1424 			LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
1425 			Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
1426 
1427 			LoadAndFormatString( hInstance, IDS_NEXT_BUTTON, szBuffer, elementsof(szBuffer) );
1428 			Button_SetText( GetDlgItem(hwndDlg, IDNEXT), szBuffer );
1429 
1430 			LoadAndFormatString( hInstance, IDS_SEND_BUTTON, szBuffer, elementsof(szBuffer) );
1431 			Button_SetText( GetDlgItem(hwndDlg, IDFINISH), szBuffer );
1432 
1433 			LoadAndFormatString( hInstance, IDS_BACK_BUTTON, szBuffer, elementsof(szBuffer) );
1434 			Button_SetText( GetDlgItem(hwndDlg, IDBACK), szBuffer );
1435 
1436 			ShowWindow( hwndPages[1], SW_HIDE );
1437 			ShowWindow( hwndPages[0], SW_SHOW );
1438 
1439 			// Let Crash Reporter window stay on top of all other windows
1440 			SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
1441 		}
1442 		return FALSE;
1443 	case WM_CTLCOLORSTATIC:
1444 		return (BOOL)CreateSolidBrush(GetSysColor(COLOR_WINDOW));
1445 	case WM_COMMAND:
1446 		switch ( LOWORD(wParam) )
1447 		{
1448 		case IDBACK:
1449 			if ( iActualPage > 0 )
1450 			{
1451 				ShowWindow( hwndPages[iActualPage], SW_HIDE );
1452 				ShowWindow( hwndPages[--iActualPage], SW_SHOW );
1453 			}
1454 			return TRUE;
1455 		case IDNEXT:
1456 			if ( iActualPage < elementsof(hwndPages) - 1 )
1457 			{
1458 				ShowWindow( hwndPages[iActualPage], SW_HIDE );
1459 				ShowWindow( hwndPages[++iActualPage], SW_SHOW );
1460 			}
1461 			return TRUE;
1462 		case IDFINISH:
1463 			{
1464 				TCHAR	szBuffer[32767];
1465 				CrashReportParams	*pParams = (CrashReportParams*)GetWindowLong( hwndDlg, GWL_USERDATA );
1466 
1467 				pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndPages[1], IDC_ALLOW_CONTACT) ) ? TRUE : FALSE;
1468 
1469 				Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) );
1470 				pParams->sTitle = szBuffer;
1471 
1472 				Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) );
1473 				pParams->sComment = szBuffer;
1474 
1475 				Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) );
1476 				pParams->sEmail = szBuffer;
1477 
1478 				if ( pParams->fAllowContact && !pParams->sEmail.length() )
1479 				{
1480 					TCHAR	szMessage[MAX_TEXT_BUFFER];
1481 
1482 					LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_NOEMAILADDRESS, szMessage, elementsof(szMessage) );
1483 
1484 					MessageBox( hwndDlg, szMessage, NULL, MB_ICONERROR | MB_OK );
1485 					break;  // Don't end the dialog
1486 				}
1487 				else
1488 				{
1489 					pParams->WriteToRegistry();
1490 
1491 					WriteCommentFile( pParams->sComment.c_str() );
1492 					WriteReportFile( pParams );
1493 
1494 					if ( !SendCrashReport( hwndDlg, *pParams ) )
1495 						break; // Don't end the dialog
1496 				}
1497 			}
1498 			// Fallthrough !!!
1499 		case IDCANCEL:
1500 			EndDialog( hwndDlg, wParam );
1501 			return TRUE;
1502 		}
1503 		break;
1504 	default:
1505 		break;
1506 	}
1507 
1508 	return FALSE;
1509 }
1510 
1511 
1512 
1513 //*****************************************************************************
1514 //* Generate MD5 checksum
1515 //*****************************************************************************
1516 
1517 #define MAGIC_DESCRIPTION_FILLER	'x'
1518 #define MAGIC_DESCRIPTION_COUNT		80
1519 
1520 static void repatch_soffice_exe( void *pBuffer, size_t nBufSize )
1521 {
1522 	wchar_t DescriptionBuffer[MAGIC_DESCRIPTION_COUNT];
1523 
1524 	memset( DescriptionBuffer, 0, sizeof(DescriptionBuffer) );
1525 	wcsncpy( DescriptionBuffer, g_wstrProductKey.c_str(), elementsof(DescriptionBuffer) - 1 );
1526 
1527 	bool bPatched = false;
1528 
1529 	do
1530 	{
1531 		void *pFound = memchr( pBuffer, ((char *)DescriptionBuffer)[0], nBufSize );
1532 
1533 		if ( pFound )
1534 		{
1535 			size_t distance = (char *)pFound - (char *)pBuffer;
1536 
1537 			if ( nBufSize >= distance )
1538 			{
1539 				nBufSize -= distance;
1540 
1541 				if ( nBufSize >= sizeof(DescriptionBuffer) &&
1542 					0 == memcmp( pFound, DescriptionBuffer, sizeof(DescriptionBuffer) ) )
1543 				{
1544 					for ( int i = 0; i < 80; i++ )
1545 					{
1546 						((wchar_t *)pFound)[i] = MAGIC_DESCRIPTION_FILLER;
1547 					}
1548 					bPatched = true;
1549 				}
1550 				else
1551 				{
1552 					pBuffer = (void *)(((char *)pFound) + 1);
1553 					nBufSize--;
1554 				}
1555 			}
1556 			else
1557 				nBufSize = 0;
1558 		}
1559 		else
1560 			nBufSize = 0;
1561 	} while ( !bPatched && nBufSize );
1562 }
1563 
1564 // Normalize executable/library images to prevent different MD5 checksums due
1565 // to a different PE header date/checksum (this doesn't affect the code/data
1566 // sections of a executable/library. Please see tools/source/bootstrp/md5.cxx
1567 // where the same method is also used. The tool so_checksum creates the MD5
1568 // checksums during build time. You have to make sure that both methods use the
1569 // same algorithm otherwise there could be problems with stack reports.
1570 static void normalize_pe_image(sal_uInt8* buffer, size_t nBufferSize)
1571 {
1572 	const int OFFSET_PE_OFFSET                  = 0x3c;
1573 	const int OFFSET_COFF_TIMEDATESTAMP         = 4;
1574 	const int PE_SIGNATURE_SIZE                 = 4;
1575 	const int COFFHEADER_SIZE                   = 20;
1576 	const int OFFSET_PE_OPTIONALHEADER_CHECKSUM = 64;
1577 
1578 	// Check the header part of the file buffer
1579 	if (buffer[0] == 'M' && buffer[1] == 'Z')
1580 	{
1581 		unsigned long PEHeaderOffset = (long)buffer[OFFSET_PE_OFFSET];
1582 		if (PEHeaderOffset < nBufferSize-4)
1583 		{
1584 			if ( buffer[PEHeaderOffset] == 'P' &&
1585 				 buffer[PEHeaderOffset+1] == 'E' &&
1586 				 buffer[PEHeaderOffset+2] == 0 &&
1587 				 buffer[PEHeaderOffset+3] == 0 )
1588 			{
1589 				PEHeaderOffset += PE_SIGNATURE_SIZE;
1590 				if (PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP < nBufferSize-4)
1591 				{
1592 					// Set timedatestamp and checksum fields to a normalized
1593 					// value to enforce the same MD5 checksum for identical
1594 					// Windows	executables/libraries.
1595 					buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP] = 0;
1596 					buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+1] = 0;
1597 					buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+2] = 0;
1598 					buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+3] = 0;
1599 				}
1600 
1601 				if (PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM < nBufferSize-4)
1602 				{
1603 					// Set checksum to a normalized value
1604 					buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM] = 0;
1605 					buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+1] = 0;
1606 					buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+2] = 0;
1607 					buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+3] = 0;
1608 				}
1609 			}
1610 		}
1611 	}
1612 }
1613 
1614 static sal_uInt32 calc_md5_checksum(  const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
1615 {
1616 	const int MINIMAL_FILESIZE = 512;
1617 
1618 	sal_uInt32	nBytesProcessed = 0;
1619 
1620 	FILE *fp = fopen( filename, "rb" );
1621 
1622 	if ( fp )
1623 	{
1624 		long	nFileSize;
1625 
1626 		if ( 0 == fseek( fp, 0, SEEK_END ) && -1 != (nFileSize = ftell(fp)) )
1627 		{
1628 			rewind( fp );
1629 
1630 			sal_uInt8 *pBuffer = new sal_uInt8[nFileSize];
1631 			size_t nBytesRead = fread( pBuffer, 1, nFileSize, fp );
1632 
1633 			if ( sal::static_int_cast<long>(nBytesRead) == nFileSize )
1634 			{
1635 				if ( 0 == stricmp( GetFileName(filename).c_str(), "soffice.bin" ) )
1636 					repatch_soffice_exe( pBuffer, nBytesRead );
1637 				else if ( nFileSize > MINIMAL_FILESIZE )
1638 					normalize_pe_image( pBuffer, nBytesRead );
1639 
1640 				rtlDigestError error = rtl_digest_MD5 (
1641 					pBuffer,   nBytesRead,
1642 					pChecksum, nChecksumLen	);
1643 
1644 				if ( rtl_Digest_E_None == error )
1645 					nBytesProcessed = nBytesRead;
1646 			}
1647 
1648 			delete[] pBuffer;
1649 		}
1650 
1651 		fclose( fp );
1652 
1653 	}
1654 
1655 	return nBytesProcessed;
1656 }
1657 
1658 #if 0
1659 static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen )
1660 {
1661 	sal_uInt32	nBytesProcessed = 0;
1662 
1663 	FILE *fp = fopen( filename, "rb" );
1664 
1665 	if ( fp )
1666 	{
1667 		rtlDigest digest = rtl_digest_createMD5();
1668 
1669 		if ( digest )
1670 		{
1671 			size_t			nBytesRead;
1672 			sal_uInt8		buffer[4096];
1673 			rtlDigestError	error = rtl_Digest_E_None;
1674 
1675 			while ( rtl_Digest_E_None == error &&
1676 				0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) )
1677 			{
1678 				error = rtl_digest_updateMD5( digest, buffer, nBytesRead );
1679 				nBytesProcessed += nBytesRead;
1680 			}
1681 
1682 			if ( rtl_Digest_E_None == error )
1683 			{
1684 				error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen );
1685 			}
1686 
1687 			if ( rtl_Digest_E_None != error )
1688 				nBytesProcessed = 0;
1689 
1690 			rtl_digest_destroyMD5( digest );
1691 		}
1692 
1693 		fclose( fp );
1694 	}
1695 
1696 	return nBytesProcessed;
1697 }
1698 
1699 #endif
1700 //***************************************************************************
1701 
1702 static bool WriteStackFile( FILE *fout, hash_map< string, string >& rLibraries, DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers )
1703 {
1704 	bool	fSuccess = false;
1705 
1706 	if ( fout && dwProcessId && pExceptionPointers )
1707 	{
1708 		HANDLE	hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
1709 
1710 		if ( IsValidHandle(hProcess) )
1711 		{
1712 			EXCEPTION_POINTERS	aExceptionPointers;
1713 			CONTEXT				aContextRecord;
1714 
1715 			ReadProcessMemory(
1716 				hProcess,
1717 				pExceptionPointers,
1718 				&aExceptionPointers,
1719 				sizeof(aExceptionPointers),
1720 				NULL );
1721 
1722 			ReadProcessMemory(
1723 				hProcess,
1724 				aExceptionPointers.ContextRecord,
1725 				&aContextRecord,
1726 				sizeof(aContextRecord),
1727 				NULL );
1728 
1729 			STACKFRAME	frame;
1730 
1731 			ZeroMemory( &frame, sizeof(frame) );
1732 			frame.AddrPC.Offset = aContextRecord.Eip;
1733 			frame.AddrPC.Mode = AddrModeFlat;
1734 			frame.AddrFrame.Offset = aContextRecord.Ebp;
1735 			frame.AddrFrame.Mode = AddrModeFlat;
1736 
1737 			BOOL bSuccess;
1738 			int frameNum = 0;
1739 
1740 			SymInitialize( hProcess, NULL, TRUE );
1741 
1742 			fprintf( fout, "<errormail:Stack type=\"Win32\">\n" );
1743 
1744 			do
1745 			{
1746 				fSuccess = true;
1747 
1748 				bSuccess = StackWalk( IMAGE_FILE_MACHINE_I386,
1749 					hProcess,
1750 					NULL,
1751 					&frame,
1752 					&aContextRecord,
1753 					(PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory,
1754 					SymFunctionTableAccess,
1755 					SymGetModuleBase,
1756 					NULL );
1757 
1758 				if ( bSuccess )
1759 				{
1760 					// Note: ImageHelp ANSI functions do not have an A postfix while
1761 					//       Unicode versions have a W postfix. There's no macro
1762 					//       that depends on define UNICODE
1763 
1764 					IMAGEHLP_MODULE	moduleInfo;
1765 
1766 					ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
1767 					moduleInfo.SizeOfStruct = sizeof(moduleInfo);
1768 
1769 					if ( SymGetModuleInfo( hProcess, frame.AddrPC.Offset, &moduleInfo ) )
1770 					{
1771 						rLibraries[ GetFileName( moduleInfo.LoadedImageName ).c_str() ] = moduleInfo.LoadedImageName;
1772 
1773 						DWORD	dwRelOffset = 0;
1774 						BYTE	symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 256 ];
1775 						PIMAGEHLP_SYMBOL	pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
1776 
1777 						ZeroMemory( symbolBuffer, sizeof(symbolBuffer) );
1778 						pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
1779 						pSymbol->MaxNameLength = 256;
1780 
1781 						if ( SymGetSymFromAddr( hProcess, frame.AddrPC.Offset, &dwRelOffset, pSymbol ) )
1782 							fprintf( fout, "<errormail:StackInfo " \
1783 								"pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" ordinal=\"%s+0x%p\" name=\"%s\" path=\"%s\"/>\n",
1784 								frameNum,
1785 								frame.AddrPC.Offset,
1786 								frame.AddrPC.Offset - moduleInfo.BaseOfImage,
1787 								xml_encode(pSymbol->Name).c_str(),
1788 								frame.AddrPC.Offset - pSymbol->Address,
1789 								xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
1790 								xml_encode( GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
1791 								);
1792 						else
1793 							fprintf( fout, "<errormail:StackInfo " \
1794 								"pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" name=\"%s\" path=\"%s\"/>\n",
1795 								frameNum,
1796 								frame.AddrPC.Offset,
1797 								frame.AddrPC.Offset - moduleInfo.BaseOfImage,
1798 								xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
1799 								xml_encode(GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
1800 								);
1801 					}
1802 					else
1803 						fprintf( fout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%p\"/>\n",
1804 							frameNum,
1805 							frame.AddrPC.Offset
1806 							);
1807 
1808 					frameNum++;
1809 				}
1810 
1811 			} while ( bSuccess );
1812 
1813 			fprintf( fout, "</errormail:Stack>\n" );
1814 
1815 			SymCleanup( hProcess );
1816 
1817 			CloseHandle( hProcess );
1818 		}
1819 
1820 	}
1821 
1822 	return fSuccess;
1823 }
1824 
1825 bool WriteChecksumFile( FILE *fchksum, const hash_map< string, string >& rLibraries )
1826 {
1827 	bool success = false;
1828 
1829 	if ( fchksum && rLibraries.size() )
1830 	{
1831 		fprintf( fchksum, "<errormail:Checksums type=\"MD5\">\n" );
1832 
1833 		hash_map< string, string >::const_iterator iter;
1834 
1835 		for ( iter = rLibraries.begin();
1836 			iter != rLibraries.end();
1837 			iter++ )
1838 		{
1839 			sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
1840 			sal_uInt32 nBytesProcessed = calc_md5_checksum(
1841 				iter->second.c_str(),
1842 				checksum, sizeof(checksum) );
1843 
1844 			if ( nBytesProcessed )
1845 			{
1846 				fprintf( fchksum, "<errormail:Checksum sum=\"0x" );
1847 				for ( int i = 0; i < sizeof(checksum); fprintf( fchksum, "%02X", checksum[i++] ) );
1848 				fprintf( fchksum, "\" bytes=\"%d\" file=\"%s\"/>\n",
1849 					nBytesProcessed,
1850 					GetFileName( iter->first ).c_str() );
1851 			}
1852 		}
1853 
1854 		fprintf( fchksum, "</errormail:Checksums>\n" );
1855 
1856 		success = true;
1857 	}
1858 
1859 	return success;
1860 }
1861 
1862 //***************************************************************************
1863 
1864 BOOL FindDumpFile()
1865 {
1866 	TCHAR	szFileName[MAX_PATH];
1867 
1868 	if ( GetCrashDataPath( szFileName ) )
1869 	{
1870 		_tcscat( szFileName, _T("\\crashdat.dmp") );
1871 
1872 		HANDLE	hFile =  CreateFile(
1873 			szFileName,
1874 			GENERIC_READ,
1875 			0, NULL,
1876 			OPEN_EXISTING,
1877 			FILE_ATTRIBUTE_NORMAL, NULL );
1878 
1879 		if ( hFile )
1880 		{
1881 			CloseHandle( hFile );
1882 
1883 			WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
1884 			_tcscpy( g_szDumpFileName, szFileName );
1885 
1886 			return TRUE;
1887 		}
1888 	}
1889 
1890 	return FALSE;
1891 }
1892 
1893 BOOL WriteDumpFile( DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers, DWORD dwThreadId )
1894 {
1895 	BOOL	fSuccess = FALSE;
1896 	PMINIDUMP_EXCEPTION_INFORMATION	lpExceptionParam = NULL;
1897 	MINIDUMP_EXCEPTION_INFORMATION	ExceptionParam;
1898 
1899 	HMODULE	hDbgHelp = LoadLibrary( _T("DBGHELP.DLL" ) );
1900 	MiniDumpWriteDump_PROC	pMiniDumpWriteDump = NULL;
1901 
1902 	if ( hDbgHelp )
1903 	{
1904 		pMiniDumpWriteDump = (MiniDumpWriteDump_PROC)GetProcAddress( hDbgHelp, "MiniDumpWriteDump" );
1905 
1906 		if ( !pMiniDumpWriteDump )
1907 		{
1908 			FreeLibrary( hDbgHelp );
1909 			return false;
1910 		}
1911 	}
1912 
1913 	if ( !pMiniDumpWriteDump )
1914 		return false;
1915 
1916 	HANDLE	hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
1917 
1918 	if ( IsValidHandle(hProcess) )
1919 	{
1920 		TCHAR	szTempPath[MAX_PATH];
1921 
1922 //		if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
1923 		if ( GetCrashDataPath( szTempPath ) )
1924 		{
1925 			TCHAR	szFileName[MAX_PATH];
1926 
1927 //			if ( GetTempFileName( szTempPath, TEXT("DMP"), 0, szFileName ) )
1928 			_tcscpy( szFileName, szTempPath );
1929 			_tcscat( szFileName, _T("\\crashdat.dmp") );
1930 			{
1931 				HANDLE	hFile =  CreateFile(
1932 					szFileName,
1933 					GENERIC_READ | GENERIC_WRITE,
1934 					0, NULL,
1935 //					OPEN_EXISTING,
1936 					CREATE_ALWAYS,
1937 					FILE_ATTRIBUTE_NORMAL, NULL );
1938 
1939 				if ( hFile )
1940 				{
1941 					if ( pExceptionPointers && dwThreadId )
1942 					{
1943 						ExceptionParam.ThreadId = dwThreadId;
1944 						ExceptionParam.ExceptionPointers = pExceptionPointers;
1945 						ExceptionParam.ClientPointers = TRUE;
1946 
1947 						EXCEPTION_POINTERS	aExceptionPointers;
1948 						EXCEPTION_RECORD	aExceptionRecord;
1949 
1950 						ReadProcessMemory(
1951 							hProcess,
1952 							pExceptionPointers,
1953 							&aExceptionPointers,
1954 							sizeof(aExceptionPointers),
1955 							NULL );
1956 
1957 
1958 						ReadProcessMemory(
1959 							hProcess,
1960 							aExceptionPointers.ExceptionRecord,
1961 							&aExceptionRecord,
1962 							sizeof(aExceptionRecord),
1963 							NULL );
1964 
1965 						g_dwExceptionCode = aExceptionRecord.ExceptionCode;
1966 
1967 						lpExceptionParam = &ExceptionParam;
1968 					}
1969 
1970 					fSuccess = pMiniDumpWriteDump( hProcess, dwProcessId, hFile, MiniDumpNormal, lpExceptionParam, NULL, NULL );
1971 
1972 					CloseHandle( hFile );
1973 
1974 					WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
1975 					_tcscpy( g_szDumpFileName, szFileName );
1976 				}
1977 
1978 				if ( !fSuccess )
1979 					DeleteFile( szFileName );
1980 			}
1981 		}
1982 
1983 		CloseHandle( hProcess );
1984 	}
1985 
1986 	FreeLibrary( hDbgHelp );
1987 
1988 	return fSuccess;
1989 }
1990 
1991 //***************************************************************************
1992 
1993 static DWORD FindProcessForImage( LPCTSTR lpImagePath )
1994 {
1995 	DWORD	dwProcessId = 0;
1996 	DWORD	aProcesses[1024];
1997 	DWORD	dwSize = 0;
1998 	TCHAR	szShortImagePath[MAX_PATH];
1999 
2000 	if ( GetShortPathName( lpImagePath, szShortImagePath, elementsof(szShortImagePath) ) &&
2001 		EnumProcesses( aProcesses, sizeof(aProcesses), &dwSize ) )
2002 	{
2003 		unsigned nProcesses = dwSize / sizeof(aProcesses[0]);
2004 
2005 		for ( unsigned i = 0; !dwProcessId && i < nProcesses; i++ )
2006 		{
2007 			HANDLE	hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
2008 
2009 			if ( IsValidHandle(hProcess) )
2010 			{
2011 				TCHAR	szModulePath[MAX_PATH+1];
2012 
2013 				if ( GetModuleFileNameEx( hProcess, NULL, szModulePath, MAX_PATH ) )
2014 				{
2015 					TCHAR	szShortModulePath[MAX_PATH];
2016 
2017 					if ( GetShortPathName( szModulePath, szShortModulePath, elementsof(szShortModulePath) ) )
2018 					{
2019 						if ( 0 == _tcsicmp( szShortModulePath, szShortImagePath ) )
2020 							dwProcessId = aProcesses[i];
2021 					}
2022 				}
2023 
2024 				CloseHandle( hProcess );
2025 			}
2026 		}
2027 	}
2028 
2029 	return dwProcessId;
2030 }
2031 //***************************************************************************
2032 
2033 static bool ParseCommandArgs( LPDWORD pdwProcessId, PEXCEPTION_POINTERS* ppException, LPDWORD pdwThreadId )
2034 {
2035 	int		argc = __argc;
2036 #ifdef __MINGW32__
2037 #ifdef _UNICODE
2038 	TCHAR	**argv = reinterpret_cast<TCHAR **>(alloca((argc+1)*sizeof(WCHAR*)));
2039 	int *sizes = reinterpret_cast<int *>(alloca(argc*sizeof(int)));
2040 	int argsize=0;
2041 	char **ptr;
2042 	int i;
2043 	ptr=__argv;
2044 	for (i = 0; i < argc; ++i)
2045 	{
2046 		sizes[i]=MultiByteToWideChar(CP_ACP, 0, *ptr, -1, NULL, 0);
2047 		argsize+=sizes[i]+1;
2048 		++ptr;
2049 	}
2050 	++argsize;
2051 	TCHAR	*args = reinterpret_cast<TCHAR *>(alloca(argsize*sizeof(WCHAR)));
2052 	ptr=__argv;
2053 	TCHAR *cptr=args;
2054 	for (i = 0; i < argc; ++i)
2055 	{
2056 		argv[i]=cptr;
2057 		MultiByteToWideChar( CP_ACP, 0, *ptr, -1, cptr, sizes[i] );
2058 		++ptr;
2059 		cptr+=sizes[i];
2060 		*cptr=0;
2061 		++cptr;
2062 	}
2063 	argv[i]=cptr;
2064 	*cptr=0;
2065 #else
2066 	TCHAR	**argv = __argv;
2067 #endif
2068 #else
2069 	TCHAR	**argv = __targv;
2070 #endif
2071 	bool	bSuccess = true;
2072 
2073 	for ( int argn = 1; bSuccess && argn < argc; argn++ )
2074 	{
2075 		if ( 0 == _tcsicmp( argv[argn], _T("-h") ) ||
2076 			 0 == _tcsicmp( argv[argn], _T("/h") ) ||
2077 			 0 == _tcsicmp( argv[argn], _T("-?") ) ||
2078 			 0 == _tcsicmp( argv[argn], _T("/?") ) ||
2079 			 0 == _tcsicmp( argv[argn], _T("/help") ) ||
2080 			 0 == _tcsicmp( argv[argn], _T("-help") ) ||
2081 			 0 == _tcsicmp( argv[argn], _T("--help") )
2082 			 )
2083 		{
2084 			HINSTANCE	hInstance = GetModuleHandle(NULL);
2085 			TCHAR	szUsage[FORMATBUFSIZE];
2086 			TCHAR	szProcess[FORMATBUFSIZE];
2087 			TCHAR	szProcessDescription[FORMATBUFSIZE];
2088 			TCHAR	szHelpDescription[FORMATBUFSIZE];
2089 
2090 			LoadAndFormatString( hInstance, IDS_MSG_CMDLINE_USAGE, szUsage, elementsof(szUsage) );
2091 			LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID, szProcess, elementsof(szProcess) );
2092 			LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID_DESCRIPTION, szProcessDescription, elementsof(szProcessDescription) );
2093 			LoadAndFormatString( hInstance, IDS_MSG_PARAM_HELP_DESCRIPTION, szHelpDescription, elementsof(szHelpDescription) );
2094 
2095 			_tprintf(
2096 				TEXT("\n%s: crashrep %s\n\n")
2097 				TEXT("/?, -h[elp]          %s\n\n")
2098 				TEXT("%-20s %s\n\n"),
2099 				szUsage, szProcess, szHelpDescription, szProcess, szProcessDescription
2100 				);
2101 
2102 			return true;
2103 		}
2104 		else if ( 0 == _tcsicmp( argv[argn], _T("-p") ) ||
2105 			 0 == _tcsicmp( argv[argn], _T("/p") ) )
2106 		{
2107 			if ( ++argn < argc )
2108 				*pdwProcessId = _tcstoul( argv[argn], NULL, 0 );
2109 			else
2110 				bSuccess = false;
2111 		}
2112 		else if ( 0 == _tcsicmp( argv[argn], _T("-excp") ) ||
2113 			      0 == _tcsicmp( argv[argn], _T("/excp") ) )
2114 		{
2115 			if ( ++argn < argc )
2116 				*ppException = (PEXCEPTION_POINTERS)_tcstoul( argv[argn], NULL, 0 );
2117 			else
2118 				bSuccess = false;
2119 		}
2120 		else if ( 0 == _tcsicmp( argv[argn], _T("-t") ) ||
2121 			      0 == _tcsicmp( argv[argn], _T("/t") ) )
2122 		{
2123 			if ( ++argn < argc )
2124 				*pdwThreadId = _tcstoul( argv[argn], NULL, 0 );
2125 			else
2126 				bSuccess = false;
2127 		}
2128 		else if ( 0 == _tcsicmp( argv[argn], _T("-noui") ) ||
2129 			      0 == _tcsicmp( argv[argn], _T("/noui") ) )
2130 		{
2131 			g_bNoUserInterface = true;
2132 		}
2133 		else if ( 0 == _tcsicmp( argv[argn], _T("-send") ) ||
2134 			      0 == _tcsicmp( argv[argn], _T("/send") ) )
2135 		{
2136 			g_bSendReport = true;
2137 		}
2138 		else if ( 0 == _tcsicmp( argv[argn], _T("-load") ) ||
2139 			      0 == _tcsicmp( argv[argn], _T("/load") ) )
2140 		{
2141 			g_bLoadReport = true;
2142 		}
2143 		else // treat parameter as image path
2144 		{
2145 			TCHAR	szImagePath[MAX_PATH];
2146 			LPTSTR	lpImageName;
2147 
2148 			if ( GetFullPathName( argv[argn], MAX_PATH, szImagePath, &lpImageName ) )
2149 			{
2150 				DWORD	dwProcessId = FindProcessForImage( szImagePath );
2151 
2152 				if ( dwProcessId )
2153 					*pdwProcessId = dwProcessId;
2154 				else
2155 					bSuccess = false;
2156 			}
2157 		}
2158 	}
2159 
2160 	if ( !*pdwProcessId && !g_bLoadReport )
2161 	{
2162 		TCHAR	szImagePath[MAX_PATH];
2163 		LPTSTR	lpImageName;
2164 
2165 		if ( GetFullPathName( TEXT("soffice.exe"), MAX_PATH, szImagePath, &lpImageName ) )
2166 		{
2167 			DWORD	dwProcessId = FindProcessForImage( szImagePath );
2168 
2169 			if ( dwProcessId )
2170 				*pdwProcessId = dwProcessId;
2171 			else
2172 				bSuccess = false;
2173 		}
2174 	}
2175 
2176 	return bSuccess;
2177 }
2178 
2179 //***************************************************************************
2180 
2181 BOOL WriteCommentFile( LPCTSTR lpComment )
2182 {
2183 	BOOL	fSuccess = FALSE;
2184 	TCHAR	szTempPath[MAX_PATH];
2185 
2186 	if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
2187 	{
2188 		TCHAR	szFileName[MAX_PATH];
2189 
2190 		if ( GetTempFileName( szTempPath, TEXT("CMT"), 0, szFileName ) )
2191 		{
2192 			HANDLE	hFile =  CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2193 
2194 			if ( hFile )
2195 			{
2196 				DWORD	dwBytesWritten;
2197 
2198 				int needed = WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, NULL, 0, NULL, NULL );
2199 				if ( needed )
2200 				{
2201 					char *lpCommentUTF8 = (char *)alloca( needed );
2202 					WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, lpCommentUTF8, needed, NULL, NULL );
2203 					fSuccess = WriteFile( hFile, lpCommentUTF8, strlen(lpCommentUTF8), &dwBytesWritten, NULL );
2204 				}
2205 				else
2206 					fSuccess = TRUE;
2207 
2208 
2209 				CloseHandle( hFile );
2210 
2211 				WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szCommentFileNameA, MAX_PATH, NULL, NULL );
2212 			}
2213 
2214 			if ( !fSuccess )
2215 				DeleteFile( szFileName );
2216 		}
2217 	}
2218 
2219 	return fSuccess;
2220 }
2221 
2222 //***************************************************************************
2223 
2224 static int _tsetenv( const _TCHAR *lpVar, const _TCHAR *lpValue )
2225 {
2226 	if ( !lpValue )
2227 		lpValue = _T("");
2228 
2229 	_TCHAR	*envstr = (TCHAR *)alloca( (_tcslen( lpVar ) + _tcslen( lpValue ) + 2) * sizeof(_TCHAR) );
2230 
2231 	_tcscpy( envstr, lpVar );
2232 	_tcscat( envstr, _T("=") );
2233 	_tcscat( envstr, lpValue );
2234 
2235 	return _tputenv( envstr );
2236 }
2237 
2238 static bool read_line( FILE *fp, string& rLine )
2239 {
2240 	char szBuffer[1024];
2241 	bool bSuccess = false;
2242 	bool bEOL = false;
2243 	string	line;
2244 
2245 
2246 	while ( !bEOL && fgets( szBuffer, sizeof(szBuffer), fp ) )
2247 	{
2248 		int	len = strlen(szBuffer);
2249 
2250 		bSuccess = true;
2251 
2252 		while ( len && szBuffer[len - 1] == '\n' )
2253 		{
2254 			szBuffer[--len] = 0;
2255 			bEOL = true;
2256 		}
2257 
2258 		line.append( szBuffer );
2259 	}
2260 
2261 	rLine = line;
2262 	return bSuccess;
2263 }
2264 
2265 static string get_script_string( const char *pFileName, const char *pKeyName )
2266 {
2267 	FILE	*fp = fopen( pFileName, "rt" );
2268 	string	retValue;
2269 
2270 	if ( fp )
2271 	{
2272 		string line;
2273 		string section;
2274 
2275 		while ( read_line( fp, line ) )
2276 		{
2277 			line = trim_string( line );
2278 
2279 
2280 			string::size_type iEqualSign = line.find( '=', 0 );
2281 
2282 			if ( iEqualSign != string::npos )
2283 			{
2284 				string	keyname = line.substr( 0, iEqualSign );
2285 				keyname = trim_string( keyname );
2286 
2287 				string	value = line.substr( sal::static_int_cast<string::size_type>(iEqualSign + 1) );
2288 				value = trim_string( value );
2289 
2290 				if ( value.length() && '\"' == value[0] )
2291 				{
2292 					value.erase( 0, 1 );
2293 
2294 					string::size_type iQuotes = value.find( '"', 0 );
2295 
2296 					if ( iQuotes != string::npos )
2297 						value.erase( iQuotes );
2298 				}
2299 
2300 				if ( 0 == stricmp( keyname.c_str(), pKeyName ) )
2301 				{
2302 					retValue = value;
2303 					break;
2304 				}
2305 			}
2306 		}
2307 
2308 		fclose( fp );
2309 	}
2310 
2311 	return retValue;
2312 }
2313 
2314 static bool ReadBootstrapParams( CrashReportParams &rParams )
2315 {
2316 	TCHAR	szBuffer[256] = TEXT("");
2317 	TCHAR	szModuleName[MAX_PATH];
2318 	TCHAR	szModuleVersionName[MAX_PATH];
2319 	TCHAR	szDrive[_MAX_DRIVE];
2320 	TCHAR	szDir[_MAX_DIR];
2321 	TCHAR	szFName[_MAX_FNAME];
2322 	TCHAR	szExt[_MAX_EXT];
2323 	TCHAR	szReportServer[MAX_HOSTNAME];
2324 	TCHAR	szReportPort[256];
2325 	bool	bSuccess = false;
2326 
2327 	GetModuleFileName( NULL, szModuleName, MAX_PATH );
2328 	_tsplitpath( szModuleName, szDrive, szDir, szFName, szExt );
2329 	_tmakepath( szModuleName, szDrive, szDir, _T("bootstrap"), _T(".ini") );
2330 	_tmakepath( szModuleVersionName, szDrive, szDir, _T("version"), _T(".ini") );
2331 
2332 	if (
2333 		GetPrivateProfileString(
2334 		TEXT("Bootstrap"),
2335 		TEXT("ProductKey"),
2336 		TEXT("OpenOffice.org"),
2337 		szBuffer,
2338 		elementsof(szBuffer),
2339 		szModuleName )
2340 		)
2341 	{
2342 		TCHAR	*pVersion = _tcschr( szBuffer, ' ' );
2343 
2344 		g_wstrProductKey = szBuffer;
2345 
2346 		if ( pVersion )
2347 		{
2348 			*pVersion = 0;
2349 			pVersion++;
2350 		}
2351 		else
2352 			pVersion = TEXT("");
2353 
2354 		if ( !_tgetenv( _T("PRODUCTNAME") ) )
2355 		{
2356 			_tsetenv( TEXT("PRODUCTNAME"), szBuffer );
2357 		}
2358 		if ( !_tgetenv( _T("PRODUCTVERSION") ) )
2359 			_tsetenv( TEXT("PRODUCTVERSION"), pVersion );
2360 	}
2361 
2362 	GetPrivateProfileString(
2363 		TEXT("Version"),
2364 		TEXT("buildid"),
2365 		TEXT("unknown"),
2366 		g_szBuildId, elementsof(g_szBuildId),
2367 		szModuleVersionName );
2368 
2369 	g_strDefaultLanguage = get_script_string( "instdb.inf", "DefaultLanguage" );
2370 
2371 	if ( GetPrivateProfileString(
2372 		TEXT("ErrorReport"),
2373 		TEXT("ErrorReportPort"),
2374 		TEXT("80"),
2375 		szReportPort, elementsof(szReportPort),
2376 		szModuleName
2377 		) )
2378 	{
2379 		TCHAR *endptr = NULL;
2380 
2381 		unsigned short uReportPort = (unsigned short)_tcstoul( szReportPort, &endptr, 10 );
2382 		if ( uReportPort )
2383 			g_uReportPort = uReportPort;
2384 	}
2385 
2386 	if ( GetPrivateProfileString(
2387 		TEXT("ErrorReport"),
2388 		TEXT("ErrorReportServer"),
2389 		TEXT(""),
2390 		szReportServer, elementsof(szReportServer),
2391 		szModuleName
2392 		) )
2393 	{
2394 		bSuccess = 0 != WideCharToMultiByte( CP_ACP, 0, szReportServer, -1, g_szReportServerA, elementsof(g_szReportServerA), NULL, NULL );
2395 	}
2396 
2397 	LPCTSTR	lpEnvString;
2398 
2399 	if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYSERVER") )) )
2400 		rParams.sProxyServer = lpEnvString;
2401 
2402 	if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYPORT") )) )
2403 		rParams.sProxyPort = lpEnvString;
2404 
2405 	if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_SENDERADDRESS") )) )
2406 		rParams.sEmail = lpEnvString;
2407 
2408 	return bSuccess;
2409 }
2410 
2411 //***************************************************************************
2412 
2413 bool SendHTTPRequest(
2414 				FILE *fp,
2415 				const char *pszServer,
2416 				unsigned short uPort = 80,
2417 				const char *pszProxyServer = NULL,
2418 				unsigned short uProxyPort = 8080 )
2419 {
2420 	bool success = false;
2421 
2422 	struct hostent *hp;
2423 
2424 	if ( pszProxyServer )
2425 		hp = gethostbyname( pszProxyServer );
2426 	else
2427 		hp = gethostbyname( pszServer );
2428 
2429 	if ( hp )
2430 	{
2431 		SOCKET	s = socket( AF_INET, SOCK_STREAM, 0 );
2432 
2433 		if ( s )
2434 		{
2435 			struct sockaddr_in address;
2436 
2437 			memcpy(&(address.sin_addr.s_addr), *(hp->h_addr_list),sizeof(struct in_addr));
2438 			address.sin_family = AF_INET;
2439 
2440 			if ( pszProxyServer )
2441 				address.sin_port = ntohs( uProxyPort );
2442 			else
2443 				address.sin_port = ntohs( uPort );
2444 
2445 			if ( 0 == connect( s, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) )
2446 			{
2447 				fseek( fp, 0, SEEK_END );
2448 				size_t length = ftell( fp );
2449 				fseek( fp, 0, SEEK_SET );
2450 
2451 				char buffer[2048];
2452 
2453 				if ( pszProxyServer )
2454 					sprintf( buffer,
2455 					"POST http://%s:%d/soap/servlet/rpcrouter HTTP/1.0\r\n"
2456 						"Content-Type: text/xml; charset=\"utf-8\"\r\n"
2457 						"Content-Length: %d\r\n"
2458 						"SOAPAction: \"\"\r\n\r\n",
2459 						pszServer,
2460 						uPort,
2461 						length
2462 						);
2463 				else
2464 					sprintf( buffer,
2465 						"POST /soap/servlet/rpcrouter HTTP/1.0\r\n"
2466 						"Content-Type: text/xml; charset=\"utf-8\"\r\n"
2467 						"Content-Length: %d\r\n"
2468 						"SOAPAction: \"\"\r\n\r\n",
2469 						length
2470 						);
2471 
2472 				if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) )
2473 				{
2474 					size_t nBytes;
2475 
2476 					do
2477 					{
2478 						nBytes = fread( buffer, 1, sizeof(buffer), fp );
2479 
2480 						if ( nBytes )
2481 							success = SOCKET_ERROR != send( s, buffer, nBytes, 0 );
2482 					} while( nBytes && success );
2483 
2484 					if ( success )
2485 					{
2486 						memset( buffer, 0, sizeof(buffer) );
2487 						success = SOCKET_ERROR != recv( s, buffer, sizeof(buffer), 0 );
2488 						if ( success )
2489 						{
2490 							char szHTTPSignature[sizeof(buffer)] = "";
2491 							unsigned uHTTPReturnCode = 0;
2492 
2493 							sscanf( buffer, "%s %d ", szHTTPSignature, &uHTTPReturnCode );
2494 							success = uHTTPReturnCode == 200;
2495 						}
2496 					}
2497 				}
2498 
2499 			}
2500 
2501 			closesocket( s );
2502 		}
2503 	}
2504 
2505 	return success;
2506 }
2507 
2508 //***************************************************************************
2509 
2510 static void WriteSOAPRequest( FILE *fp )
2511 {
2512 	fprintf( fp,
2513 		"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2514 		"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
2515 		"xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
2516 		"xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\"\n"
2517 		"xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\n"
2518 		"xmlns:rds=\"urn:ReportDataService\"\n"
2519 		"xmlns:apache=\"http://xml.apache.org/xml-soap\"\n"
2520 		"SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
2521 		"<SOAP-ENV:Body>\n"
2522 		);
2523 
2524 	fprintf( fp, "<rds:submitReport>\n"  );
2525 	fprintf( fp, "<body xsi:type=\"xsd:string\">This is an autogenerated crash report mail.</body>\n" );
2526 	fprintf( fp, "<hash xsi:type=\"apache:Map\">\n" );
2527 
2528 	FILE	*fpin = fopen( g_szReportFileNameA, "r" );
2529 	if ( fpin )
2530 	{
2531 		fprintf( fp,
2532 			"<item>\n"
2533 			"<key xsi:type=\"xsd:string\">reportmail.xml</key>\n"
2534 			"<value xsi:type=\"xsd:string\"><![CDATA[" );
2535 		fcopy( fpin, fp );
2536 		fprintf( fp, "]]></value></item>\n" );
2537 		fclose( fpin );
2538 	}
2539 
2540 	fpin = fopen( g_szCommentFileNameA, "r" );
2541 	if ( fpin )
2542 	{
2543 		fprintf( fp,
2544 			"<item>\n"
2545 			"<key xsi:type=\"xsd:string\">description.txt</key>\n"
2546 			"<value xsi:type=\"xsd:string\"><![CDATA[" );
2547 		fcopy( fpin, fp );
2548 		fprintf( fp, "]]></value></item>\n" );
2549 		fclose( fpin );
2550 	};
2551 
2552 
2553 	fpin = fopen( g_szDumpFileNameA, "rb" );
2554 	if ( fpin )
2555 	{
2556 		FILE *fptemp = _tmpfile();
2557 
2558 		if ( fptemp )
2559 		{
2560 			if ( base64_encode( fpin, fptemp ) )
2561 			{
2562 				fseek( fptemp, 0, SEEK_SET );
2563 				fprintf( fp,
2564 					"<item>\n"
2565 					"<key xsi:type=\"xsd:string\">user.dmp</key>\n"
2566 					"<value xsi:type=\"xsd:string\">" );
2567 				fcopy( fptemp, fp );
2568 				fprintf( fp, "</value></item>\n" );
2569 			}
2570 			fclose( fptemp );
2571 		}
2572 		fclose( fpin );
2573 	}
2574 
2575 	fprintf( fp,
2576 		"</hash>\n"
2577 		"</rds:submitReport>\n"
2578 		"</SOAP-ENV:Body>\n"
2579 		"</SOAP-ENV:Envelope>\n"
2580 		);
2581 }
2582 
2583 //***************************************************************************
2584 
2585 struct RequestParams
2586 {
2587 	bool	success;
2588 	FILE	*fpin;
2589 	const char *lpServer;
2590 	unsigned short uPort;
2591 	const char *lpProxyServer;
2592 	unsigned short uProxyPort;
2593 	HWND	hwndStatus;
2594 };
2595 
2596 void _cdecl SendingThread( void *lpArgs )
2597 {
2598 	RequestParams *pParams = (RequestParams *)lpArgs;
2599 
2600     pParams->success = SendHTTPRequest( pParams->fpin, pParams->lpServer, pParams->uPort, pParams->lpProxyServer, pParams->uProxyPort );
2601 
2602 	PostMessage( pParams->hwndStatus, WM_COMMAND, IDOK, 0 );
2603 }
2604 
2605 //***************************************************************************
2606 
2607 BOOL CALLBACK SendingStatusDialogProc(
2608 	HWND hwndDlg,
2609 	UINT uMsg,
2610 	WPARAM wParam,
2611 	LPARAM lParam
2612 	)
2613 {
2614 	static RequestParams *pRequest = NULL;
2615 	static HANDLE hSendingThread = NULL;
2616 
2617 	switch ( uMsg )
2618 	{
2619 	case WM_INITDIALOG:
2620 		{
2621 			TCHAR	szBuffer[1024] = TEXT("");
2622 			HINSTANCE	hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE );
2623 			//HWND	hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT );
2624 
2625 			pRequest = (RequestParams *)lParam;
2626 
2627 			LoadAndFormatString( hInstance, IDS_SENDING_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
2628 			SetWindowText( hwndDlg, szBuffer );
2629 
2630 			LoadAndFormatString( hInstance, IDS_SENDING_REPORT_STATUS, szBuffer, elementsof(szBuffer) );
2631 			Static_SetText( GetDlgItem(hwndDlg, IDC_SENDING_REPORT_STATUS), szBuffer );
2632 
2633 			LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
2634 			Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
2635 
2636 			pRequest->hwndStatus = hwndDlg;
2637 
2638 			hSendingThread = (HANDLE)_beginthread( SendingThread, 0, pRequest );
2639 		}
2640 		return TRUE;
2641 	case WM_COMMAND:
2642 		switch ( LOWORD(wParam) )
2643 		{
2644 		case IDCANCEL:
2645 			TerminateThread( hSendingThread, 0 );
2646 		case IDOK:
2647 			WaitForSingleObject( hSendingThread, INFINITE );
2648 			CloseHandle( hSendingThread );
2649 			EndDialog( hwndDlg, wParam );
2650 			return TRUE;
2651 		}
2652 		break;
2653 	default:
2654 		break;
2655 	}
2656 
2657 	return FALSE;
2658 }
2659 
2660 //***************************************************************************
2661 
2662 bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams )
2663 {
2664 	bool success = false;
2665 	char szProxyServer[1024] = "";
2666 	unsigned short uProxyPort = 8080;
2667 	TCHAR *endptr = NULL;
2668 
2669 	switch ( rParams.uInternetConnection )
2670 	{
2671 	case 2:
2672 		{
2673 			WideCharToMultiByte(
2674 				CP_ACP, 0, rParams.sProxyServer.c_str(), -1,
2675 				szProxyServer, sizeof(szProxyServer), NULL, NULL );
2676 			uProxyPort = (unsigned short)_tcstoul( rParams.sProxyPort.c_str(), &endptr, 10 );
2677 		}
2678 		break;
2679 	case 0:
2680 		{
2681 			DWORD	dwProxyEnable = 0;
2682 
2683 			RegReadValue( HKEY_CURRENT_USER,
2684 				TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
2685 				TEXT("ProxyEnable"),
2686 				&dwProxyEnable,
2687 				sizeof(dwProxyEnable) );
2688 
2689 			if ( dwProxyEnable )
2690 			{
2691 				TCHAR	tszProxyServers[1024] = TEXT("");
2692 
2693 				if ( ERROR_SUCCESS == RegReadValue( HKEY_CURRENT_USER,
2694 					TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),				TEXT("ProxyServer"),
2695 					tszProxyServers,
2696 					sizeof(tszProxyServers) ) )
2697 				{
2698 					TCHAR *lpHttpStart = _tcsstr( tszProxyServers, TEXT("http=") );
2699 
2700 					if ( lpHttpStart )
2701 						lpHttpStart += 5;
2702 					else
2703 						lpHttpStart = tszProxyServers;
2704 
2705 					TCHAR *lpHttpEnd = _tcschr( lpHttpStart, ';' );
2706 
2707 					if ( lpHttpEnd )
2708 						*lpHttpEnd = 0;
2709 
2710 					char	szHTTPProxyServer[1024] = "";
2711 					WideCharToMultiByte( CP_ACP, 0, lpHttpStart, -1, szHTTPProxyServer, sizeof(szHTTPProxyServer), NULL, NULL );
2712 
2713 					char *lpColon = strchr( szHTTPProxyServer, ':' );
2714 
2715 					if ( lpColon )
2716 					{
2717 						char *endptr = NULL;
2718 
2719 						*lpColon = 0;
2720 						uProxyPort = (unsigned short)strtoul( lpColon + 1, &endptr, 10 );
2721 					}
2722 					else
2723 						uProxyPort = 8080;
2724 
2725 					strcpy( szProxyServer, szHTTPProxyServer );
2726 
2727 				}
2728 			}
2729 		}
2730 		break;
2731 	default:
2732 	case 1:
2733 		break;
2734 	}
2735 
2736 	FILE	*fptemp = _tmpfile();
2737 	if ( fptemp )
2738 	{
2739 		RequestParams	request;
2740 
2741 		request.success = false;
2742 		request.fpin = fptemp;
2743 		request.lpServer = REPORT_SERVER;
2744 		request.uPort = REPORT_PORT;
2745 		request.lpProxyServer = szProxyServer[0] ? szProxyServer : NULL;
2746 		request.uProxyPort = uProxyPort;
2747 		request.hwndStatus = NULL;
2748 
2749 		WriteSOAPRequest( fptemp );
2750 		fseek( fptemp, 0, SEEK_SET );
2751 
2752 		if ( hwndParent )
2753 		{
2754 			int retid = DialogBoxParam(
2755 				GetModuleHandle(NULL),
2756 				MAKEINTRESOURCE(IDD_SENDING_STATUS),
2757 				hwndParent,
2758 				SendingStatusDialogProc,
2759 				(LPARAM)&request
2760 				);
2761 
2762 			success = request.success;
2763 
2764 			if ( IDOK == retid )
2765 			{
2766 				if ( !success )
2767 				{
2768 					TCHAR	szMessage[1024];
2769 
2770 					LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
2771 
2772 					MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
2773 				}
2774 				else
2775 				{
2776 					TCHAR	szMessage[1024];
2777 					TCHAR	szTitle[1024];
2778 
2779 					LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
2780 					LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_HEADER, szTitle, elementsof(szTitle) );
2781 
2782 					MessageBox( hwndParent, szMessage, szTitle, MB_ICONINFORMATION | MB_OK );
2783 				}
2784 			}
2785 
2786 		}
2787 		else
2788 		{
2789 			HANDLE hSendingThread = (HANDLE)_beginthread( SendingThread, 0, (void *)&request );
2790 
2791 			WaitForSingleObject( hSendingThread, INFINITE );
2792 
2793 			success = request.success;
2794 			if ( !success )
2795 			{
2796 				TCHAR	szMessage[1024];
2797 
2798 				LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
2799 				_ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
2800 			}
2801 			else
2802 			{
2803 				TCHAR	szMessage[1024];
2804 
2805 				LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
2806 
2807 				_ftprintf( stderr, _T("SUCCESS: %s\n"), szMessage );
2808 			}
2809 		}
2810 		fclose( fptemp );
2811 	}
2812 	else
2813 	{
2814 		TCHAR	szMessage[1024];
2815 
2816 		LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_DISK_FULL, szMessage, elementsof(szMessage) );
2817 
2818 		if ( hwndParent )
2819 			MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
2820 		else
2821 			_ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
2822 	}
2823 
2824 	return success;
2825 }
2826 
2827 //***************************************************************************
2828 
2829 #ifdef __MINGW32__
2830 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR /*lpCmdLine*/, int )
2831 #else
2832 int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR /*lpCmdLine*/, int )
2833 #endif
2834 {
2835 	int exitcode = -1;
2836 	int argc = __argc;
2837 
2838 #ifdef __MINGW32__
2839 	char **argv = __argv;
2840 #else
2841 #ifdef _UNICODE
2842 	char **argv = new char *[argc + 1];
2843 
2844 	for ( int argn = 0; argn < argc; argn++ )
2845 	{
2846 		int nBytes = WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, NULL, 0, NULL, NULL );
2847 		argv[argn] = new char[nBytes];
2848 		WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, argv[argn], nBytes, NULL, NULL );
2849 	}
2850 	argv[argc] = NULL;
2851 #else
2852 	char **argv = __targv;
2853 #endif
2854 #endif
2855 
2856 	osl_setCommandArgs( argc, argv );
2857 
2858 	PEXCEPTION_POINTERS	pExceptionPointers = NULL;
2859 	DWORD				dwProcessId = 0;
2860 	DWORD				dwThreadId = 0;
2861 
2862 	WSADATA wsaData;
2863 	WORD    wVersionRequested;
2864 
2865 	wVersionRequested = MAKEWORD(1, 1);
2866 	WSAStartup(wVersionRequested, &wsaData);
2867 
2868 	CrashReportParams	Params;
2869 
2870 	Params.ReadFromRegistry();
2871 	Params.ReadFromEnvironment();
2872 
2873 	if ( ReadBootstrapParams( Params ) &&
2874 		ParseCommandArgs( &dwProcessId, &pExceptionPointers, &dwThreadId ) )
2875 	{
2876 		bool	bGotDumpFile;
2877 
2878 		if ( g_bLoadReport )
2879 			bGotDumpFile = FindDumpFile();
2880 		else
2881 			bGotDumpFile = WriteDumpFile( dwProcessId, pExceptionPointers, dwThreadId );
2882 
2883 		if( bGotDumpFile )
2884 		{
2885 			hash_map< string, string > aLibraries;
2886 
2887 			if ( g_bLoadReport )
2888 			{
2889 				g_fpStackFile = _open_reportfile( _T(".stk"), _T("rb") );
2890 				g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("rb") );
2891 			}
2892 			else
2893 			{
2894 				if ( g_bSendReport )
2895 				{
2896 					g_fpStackFile = _tmpfile();
2897 					g_fpChecksumFile = _tmpfile();
2898 				}
2899 				else
2900 				{
2901 					g_fpStackFile = _open_reportfile( _T(".stk"), _T("w+b") );
2902 					g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("w+b") );
2903 
2904 					FILE	*fpUnsent = _open_reportfile( _T(".lck"), _T("w+b") );
2905 					if ( fpUnsent )
2906 					{
2907 						fprintf( fpUnsent, "Unsent\r\n" );
2908 						fclose( fpUnsent );
2909 					}
2910 				}
2911 
2912 				WriteStackFile( g_fpStackFile, aLibraries, dwProcessId, pExceptionPointers );
2913 				WriteChecksumFile( g_fpChecksumFile, aLibraries );
2914 				WriteReportFile( &Params );
2915 
2916 				FILE	*fpPreview = _open_reportfile( _T(".prv"), _T("w+b") );
2917 
2918 				if ( fpPreview )
2919 				{
2920 					FILE	 *fp = fopen( g_szReportFileNameA, "rb" );
2921 					if ( fp )
2922 					{
2923 						fcopy( fp, fpPreview );
2924 						fclose( fp );
2925 					}
2926 					fclose( fpPreview );
2927 				}
2928 			}
2929 
2930 			if ( g_bSendReport )
2931 			{
2932 				InitCommonControls();
2933 
2934 				// Actually this should never be true anymore
2935 				if ( !g_bNoUserInterface && InitRichEdit() )
2936 				{
2937 
2938 					INT_PTR result = DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG_FRAME), NULL, DialogProc, (LPARAM)&Params );
2939 
2940 					if ( result > 0 )
2941 					{
2942 						exitcode = 0;
2943 					}
2944 					DeinitRichEdit();
2945 				}
2946 				else
2947 				{
2948 					WriteCommentFile( Params.sComment.c_str() );
2949 					WriteReportFile( &Params );
2950 					if ( SendCrashReport( NULL, Params ) )
2951 						exitcode = 0;
2952 				}
2953 
2954 
2955 				if ( g_szReportFileNameA[0] )
2956 					DeleteFileA( g_szReportFileNameA );
2957 
2958 				if ( g_szCommentFileNameA[0] )
2959 					DeleteFileA( g_szCommentFileNameA );
2960 			}
2961 			else
2962 			{
2963 				if ( g_szReportFileNameA[0] )
2964 					DeleteFileA( g_szReportFileNameA );
2965 				exitcode = 0;
2966 			}
2967 
2968 			if ( g_szDumpFileNameA[0] && g_bSendReport )
2969 					DeleteFileA( g_szDumpFileNameA );
2970 
2971 			if ( g_fpStackFile )
2972 				fclose( g_fpStackFile );
2973 
2974 			if ( g_fpChecksumFile )
2975 				fclose( g_fpChecksumFile );
2976 		}
2977 	}
2978 
2979 
2980 	return exitcode;
2981 }
2982 
2983