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