xref: /trunk/main/crashrep/source/win32/soreport.cpp (revision ebdb555ed23b18f1315977848b5cb6823d97c054)
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 
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 
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( (intptr_t)hFile, 0 );
170 
171                 fp = _fdopen( fd, "w+b" );
172             }
173         }
174     }
175 
176     return fp;
177 }
178 //***************************************************************************
179 
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 
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 
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 
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 
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 
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 
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 
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 
472 static BOOL WINAPI InitRichEdit()
473 {
474     return (NULL != LoadLibrary( RICHEDIT ));
475 }
476 
477 //***************************************************************************
478 
479 static BOOL WINAPI DeinitRichEdit()
480 {
481     return FreeLibrary( GetModuleHandle( RICHEDIT ) );
482 }
483 
484 //***************************************************************************
485 
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 
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 
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 
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 
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 
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 
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 
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 
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( (intptr_t)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 
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 
779 static BOOL ScreenToClientRect( HWND hwnd, LPRECT lprc )
780 {
781     return ScreenToClient( hwnd, (LPPOINT)&lprc->left ) && ScreenToClient( hwnd, (LPPOINT)&lprc->right );
782 }
783 
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 
794 static BOOL SetGrowMode( HWND hwnd, DWORD dwGrowMode )
795 {
796     return SetProp( hwnd, TEXT("GrowMode"), (HANDLE)dwGrowMode );
797 }
798 
799 static DWORD GetGrowMode( HWND hwnd )
800 {
801     return (DWORD)GetProp( hwnd, TEXT("GrowMode") );
802 }
803 
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 
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 
861 INT_PTR 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)GetWindowLongPtr( hwndDlg, GWLP_HINSTANCE );
896             HWND    hwndParent = (HWND)GetWindowLongPtr( hwndDlg, GWLP_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 
998 static void PreviewReport( HWND hwndParent, CrashReportParams *pParams )
999 {
1000     HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndParent, GWLP_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 //***************************************************************************
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 
1031 INT_PTR 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)GetWindowLongPtr( hwndDlg, GWLP_HINSTANCE );
1046             //HWND  hwndParent = (HWND)GetWindowLongPtr( hwndDlg, GWLP_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 
1133 static void OptionsDialog( HWND hwndParent, CrashReportParams *pParams )
1134 {
1135     HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndParent, GWLP_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 
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 
1161 INT_PTR 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*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_USERDATA );
1173             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_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)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1218             CrashReportParams   *pParams = (CrashReportParams*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_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             SetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWLP_STYLE,
1240                 GetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWLP_STYLE) | BS_DEFPUSHBUTTON );
1241             SetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDBACK), GWLP_STYLE,
1242                 GetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDBACK), GWLP_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*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_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*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_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 
1293 INT_PTR CALLBACK WelcomeDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
1294 {
1295     switch ( uMsg )
1296     {
1297     case WM_INITDIALOG:
1298         {
1299             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_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)GetWindowLongPtr(hwndDlg, GWLP_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 
1383 INT_PTR 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)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1393             TCHAR       szBuffer[FORMATBUFSIZE];
1394 
1395             SetWindowLongPtr( hwndDlg, GWLP_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*)GetWindowLongPtr( hwndDlg, GWLP_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 
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.
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 
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 
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 #if defined(INTEL)
1729             frame.AddrPC.Offset = aContextRecord.Eip;
1730 #elif defined(X86_64)
1731             frame.AddrPC.Offset = aContextRecord.Rip;
1732 #else
1733 #error Unsupported architecture
1734 #endif
1735             frame.AddrPC.Mode = AddrModeFlat;
1736 #if defined(INTEL)
1737             frame.AddrFrame.Offset = aContextRecord.Ebp;
1738 #elif defined(X86_64)
1739             frame.AddrFrame.Offset = aContextRecord.Rbp;
1740 #else
1741 #error Unsupported architecture
1742 #endif
1743             frame.AddrFrame.Mode = AddrModeFlat;
1744 
1745             BOOL bSuccess;
1746             int frameNum = 0;
1747 
1748             SymInitialize( hProcess, NULL, TRUE );
1749 
1750             fprintf( fout, "<errormail:Stack type=\"Win32\">\n" );
1751 
1752             do
1753             {
1754                 fSuccess = true;
1755 
1756                 bSuccess = StackWalk( IMAGE_FILE_MACHINE_I386,
1757                     hProcess,
1758                     NULL,
1759                     &frame,
1760                     &aContextRecord,
1761                     (PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory,
1762                     SymFunctionTableAccess,
1763                     SymGetModuleBase,
1764                     NULL );
1765 
1766                 if ( bSuccess )
1767                 {
1768                     // Note: ImageHelp ANSI functions do not have an A postfix while
1769                     //       Unicode versions have a W postfix. There's no macro
1770                     //       that depends on define UNICODE
1771 
1772                     IMAGEHLP_MODULE moduleInfo;
1773 
1774                     ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
1775                     moduleInfo.SizeOfStruct = sizeof(moduleInfo);
1776 
1777                     if ( SymGetModuleInfo( hProcess, frame.AddrPC.Offset, &moduleInfo ) )
1778                     {
1779                         rLibraries[ GetFileName( moduleInfo.LoadedImageName ).c_str() ] = moduleInfo.LoadedImageName;
1780 
1781                         DWORD64 dwRelOffset = 0;
1782                         BYTE    symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 256 ];
1783                         PIMAGEHLP_SYMBOL    pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
1784 
1785                         ZeroMemory( symbolBuffer, sizeof(symbolBuffer) );
1786                         pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
1787                         pSymbol->MaxNameLength = 256;
1788 
1789                         if ( SymGetSymFromAddr( hProcess, frame.AddrPC.Offset, &dwRelOffset, pSymbol ) )
1790                             fprintf( fout, "<errormail:StackInfo " \
1791                                 "pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" ordinal=\"%s+0x%p\" name=\"%s\" path=\"%s\"/>\n",
1792                                 frameNum,
1793                                 frame.AddrPC.Offset,
1794                                 frame.AddrPC.Offset - moduleInfo.BaseOfImage,
1795                                 xml_encode(pSymbol->Name).c_str(),
1796                                 frame.AddrPC.Offset - pSymbol->Address,
1797                                 xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
1798                                 xml_encode( GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
1799                                 );
1800                         else
1801                             fprintf( fout, "<errormail:StackInfo " \
1802                                 "pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" name=\"%s\" path=\"%s\"/>\n",
1803                                 frameNum,
1804                                 frame.AddrPC.Offset,
1805                                 frame.AddrPC.Offset - moduleInfo.BaseOfImage,
1806                                 xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
1807                                 xml_encode(GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
1808                                 );
1809                     }
1810                     else
1811                         fprintf( fout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%p\"/>\n",
1812                             frameNum,
1813                             frame.AddrPC.Offset
1814                             );
1815 
1816                     frameNum++;
1817                 }
1818 
1819             } while ( bSuccess );
1820 
1821             fprintf( fout, "</errormail:Stack>\n" );
1822 
1823             SymCleanup( hProcess );
1824 
1825             CloseHandle( hProcess );
1826         }
1827 
1828     }
1829 
1830     return fSuccess;
1831 }
1832 
1833 bool WriteChecksumFile( FILE *fchksum, const hash_map< string, string >& rLibraries )
1834 {
1835     bool success = false;
1836 
1837     if ( fchksum && rLibraries.size() )
1838     {
1839         fprintf( fchksum, "<errormail:Checksums type=\"MD5\">\n" );
1840 
1841         hash_map< string, string >::const_iterator iter;
1842 
1843         for ( iter = rLibraries.begin();
1844             iter != rLibraries.end();
1845             iter++ )
1846         {
1847             sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
1848             sal_uInt32 nBytesProcessed = calc_md5_checksum(
1849                 iter->second.c_str(),
1850                 checksum, sizeof(checksum) );
1851 
1852             if ( nBytesProcessed )
1853             {
1854                 fprintf( fchksum, "<errormail:Checksum sum=\"0x" );
1855                 for ( int i = 0; i < sizeof(checksum); fprintf( fchksum, "%02X", checksum[i++] ) );
1856                 fprintf( fchksum, "\" bytes=\"%d\" file=\"%s\"/>\n",
1857                     nBytesProcessed,
1858                     GetFileName( iter->first ).c_str() );
1859             }
1860         }
1861 
1862         fprintf( fchksum, "</errormail:Checksums>\n" );
1863 
1864         success = true;
1865     }
1866 
1867     return success;
1868 }
1869 
1870 //***************************************************************************
1871 
1872 BOOL FindDumpFile()
1873 {
1874     TCHAR   szFileName[MAX_PATH];
1875 
1876     if ( GetCrashDataPath( szFileName ) )
1877     {
1878         _tcscat( szFileName, _T("\\crashdat.dmp") );
1879 
1880         HANDLE  hFile = CreateFile(
1881             szFileName,
1882             GENERIC_READ,
1883             0, NULL,
1884             OPEN_EXISTING,
1885             FILE_ATTRIBUTE_NORMAL, NULL );
1886 
1887         if ( hFile )
1888         {
1889             CloseHandle( hFile );
1890 
1891             WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
1892             _tcscpy( g_szDumpFileName, szFileName );
1893 
1894             return TRUE;
1895         }
1896     }
1897 
1898     return FALSE;
1899 }
1900 
1901 BOOL WriteDumpFile( DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers, DWORD dwThreadId )
1902 {
1903     BOOL    fSuccess = FALSE;
1904     PMINIDUMP_EXCEPTION_INFORMATION lpExceptionParam = NULL;
1905     MINIDUMP_EXCEPTION_INFORMATION  ExceptionParam;
1906 
1907     HMODULE hDbgHelp = LoadLibrary( _T("DBGHELP.DLL" ) );
1908     MiniDumpWriteDump_PROC  pMiniDumpWriteDump = NULL;
1909 
1910     if ( hDbgHelp )
1911     {
1912         pMiniDumpWriteDump = (MiniDumpWriteDump_PROC)GetProcAddress( hDbgHelp, "MiniDumpWriteDump" );
1913 
1914         if ( !pMiniDumpWriteDump )
1915         {
1916             FreeLibrary( hDbgHelp );
1917             return false;
1918         }
1919     }
1920 
1921     if ( !pMiniDumpWriteDump )
1922         return false;
1923 
1924     HANDLE  hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
1925 
1926     if ( IsValidHandle(hProcess) )
1927     {
1928         TCHAR   szTempPath[MAX_PATH];
1929 
1930 //      if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
1931         if ( GetCrashDataPath( szTempPath ) )
1932         {
1933             TCHAR   szFileName[MAX_PATH];
1934 
1935 //          if ( GetTempFileName( szTempPath, TEXT("DMP"), 0, szFileName ) )
1936             _tcscpy( szFileName, szTempPath );
1937             _tcscat( szFileName, _T("\\crashdat.dmp") );
1938             {
1939                 HANDLE  hFile = CreateFile(
1940                     szFileName,
1941                     GENERIC_READ | GENERIC_WRITE,
1942                     0, NULL,
1943 //                  OPEN_EXISTING,
1944                     CREATE_ALWAYS,
1945                     FILE_ATTRIBUTE_NORMAL, NULL );
1946 
1947                 if ( hFile )
1948                 {
1949                     if ( pExceptionPointers && dwThreadId )
1950                     {
1951                         ExceptionParam.ThreadId = dwThreadId;
1952                         ExceptionParam.ExceptionPointers = pExceptionPointers;
1953                         ExceptionParam.ClientPointers = TRUE;
1954 
1955                         EXCEPTION_POINTERS  aExceptionPointers;
1956                         EXCEPTION_RECORD    aExceptionRecord;
1957 
1958                         ReadProcessMemory(
1959                             hProcess,
1960                             pExceptionPointers,
1961                             &aExceptionPointers,
1962                             sizeof(aExceptionPointers),
1963                             NULL );
1964 
1965 
1966                         ReadProcessMemory(
1967                             hProcess,
1968                             aExceptionPointers.ExceptionRecord,
1969                             &aExceptionRecord,
1970                             sizeof(aExceptionRecord),
1971                             NULL );
1972 
1973                         g_dwExceptionCode = aExceptionRecord.ExceptionCode;
1974 
1975                         lpExceptionParam = &ExceptionParam;
1976                     }
1977 
1978                     fSuccess = pMiniDumpWriteDump( hProcess, dwProcessId, hFile, MiniDumpNormal, lpExceptionParam, NULL, NULL );
1979 
1980                     CloseHandle( hFile );
1981 
1982                     WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
1983                     _tcscpy( g_szDumpFileName, szFileName );
1984                 }
1985 
1986                 if ( !fSuccess )
1987                     DeleteFile( szFileName );
1988             }
1989         }
1990 
1991         CloseHandle( hProcess );
1992     }
1993 
1994     FreeLibrary( hDbgHelp );
1995 
1996     return fSuccess;
1997 }
1998 
1999 //***************************************************************************
2000 
2001 static DWORD FindProcessForImage( LPCTSTR lpImagePath )
2002 {
2003     DWORD   dwProcessId = 0;
2004     DWORD   aProcesses[1024];
2005     DWORD   dwSize = 0;
2006     TCHAR   szShortImagePath[MAX_PATH];
2007 
2008     if ( GetShortPathName( lpImagePath, szShortImagePath, elementsof(szShortImagePath) ) &&
2009         EnumProcesses( aProcesses, sizeof(aProcesses), &dwSize ) )
2010     {
2011         unsigned nProcesses = dwSize / sizeof(aProcesses[0]);
2012 
2013         for ( unsigned i = 0; !dwProcessId && i < nProcesses; i++ )
2014         {
2015             HANDLE  hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
2016 
2017             if ( IsValidHandle(hProcess) )
2018             {
2019                 TCHAR   szModulePath[MAX_PATH+1];
2020 
2021                 if ( GetModuleFileNameEx( hProcess, NULL, szModulePath, MAX_PATH ) )
2022                 {
2023                     TCHAR   szShortModulePath[MAX_PATH];
2024 
2025                     if ( GetShortPathName( szModulePath, szShortModulePath, elementsof(szShortModulePath) ) )
2026                     {
2027                         if ( 0 == _tcsicmp( szShortModulePath, szShortImagePath ) )
2028                             dwProcessId = aProcesses[i];
2029                     }
2030                 }
2031 
2032                 CloseHandle( hProcess );
2033             }
2034         }
2035     }
2036 
2037     return dwProcessId;
2038 }
2039 //***************************************************************************
2040 
2041 static bool ParseCommandArgs( LPDWORD pdwProcessId, PEXCEPTION_POINTERS* ppException, LPDWORD pdwThreadId )
2042 {
2043     int     argc = __argc;
2044 #ifdef __MINGW32__
2045 #ifdef _UNICODE
2046     TCHAR   **argv = reinterpret_cast<TCHAR **>(alloca((argc+1)*sizeof(WCHAR*)));
2047     int *sizes = reinterpret_cast<int *>(alloca(argc*sizeof(int)));
2048     int argsize=0;
2049     char **ptr;
2050     int i;
2051     ptr=__argv;
2052     for (i = 0; i < argc; ++i)
2053     {
2054         sizes[i]=MultiByteToWideChar(CP_ACP, 0, *ptr, -1, NULL, 0);
2055         argsize+=sizes[i]+1;
2056         ++ptr;
2057     }
2058     ++argsize;
2059     TCHAR   *args = reinterpret_cast<TCHAR *>(alloca(argsize*sizeof(WCHAR)));
2060     ptr=__argv;
2061     TCHAR *cptr=args;
2062     for (i = 0; i < argc; ++i)
2063     {
2064         argv[i]=cptr;
2065         MultiByteToWideChar( CP_ACP, 0, *ptr, -1, cptr, sizes[i] );
2066         ++ptr;
2067         cptr+=sizes[i];
2068         *cptr=0;
2069         ++cptr;
2070     }
2071     argv[i]=cptr;
2072     *cptr=0;
2073 #else
2074     TCHAR   **argv = __argv;
2075 #endif
2076 #else
2077     TCHAR   **argv = __targv;
2078 #endif
2079     bool    bSuccess = true;
2080 
2081     for ( int argn = 1; bSuccess && argn < argc; argn++ )
2082     {
2083         if ( 0 == _tcsicmp( argv[argn], _T("-h") ) ||
2084              0 == _tcsicmp( argv[argn], _T("/h") ) ||
2085              0 == _tcsicmp( argv[argn], _T("-?") ) ||
2086              0 == _tcsicmp( argv[argn], _T("/?") ) ||
2087              0 == _tcsicmp( argv[argn], _T("/help") ) ||
2088              0 == _tcsicmp( argv[argn], _T("-help") ) ||
2089              0 == _tcsicmp( argv[argn], _T("--help") )
2090              )
2091         {
2092             HINSTANCE   hInstance = GetModuleHandle(NULL);
2093             TCHAR   szUsage[FORMATBUFSIZE];
2094             TCHAR   szProcess[FORMATBUFSIZE];
2095             TCHAR   szProcessDescription[FORMATBUFSIZE];
2096             TCHAR   szHelpDescription[FORMATBUFSIZE];
2097 
2098             LoadAndFormatString( hInstance, IDS_MSG_CMDLINE_USAGE, szUsage, elementsof(szUsage) );
2099             LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID, szProcess, elementsof(szProcess) );
2100             LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID_DESCRIPTION, szProcessDescription, elementsof(szProcessDescription) );
2101             LoadAndFormatString( hInstance, IDS_MSG_PARAM_HELP_DESCRIPTION, szHelpDescription, elementsof(szHelpDescription) );
2102 
2103             _tprintf(
2104                 TEXT("\n%s: crashrep %s\n\n")
2105                 TEXT("/?, -h[elp]          %s\n\n")
2106                 TEXT("%-20s %s\n\n"),
2107                 szUsage, szProcess, szHelpDescription, szProcess, szProcessDescription
2108                 );
2109 
2110             return true;
2111         }
2112         else if ( 0 == _tcsicmp( argv[argn], _T("-p") ) ||
2113              0 == _tcsicmp( argv[argn], _T("/p") ) )
2114         {
2115             if ( ++argn < argc )
2116                 *pdwProcessId = _tcstoul( argv[argn], NULL, 0 );
2117             else
2118                 bSuccess = false;
2119         }
2120         else if ( 0 == _tcsicmp( argv[argn], _T("-excp") ) ||
2121                   0 == _tcsicmp( argv[argn], _T("/excp") ) )
2122         {
2123             if ( ++argn < argc )
2124                 *ppException = (PEXCEPTION_POINTERS)_tcstoul( argv[argn], NULL, 0 );
2125             else
2126                 bSuccess = false;
2127         }
2128         else if ( 0 == _tcsicmp( argv[argn], _T("-t") ) ||
2129                   0 == _tcsicmp( argv[argn], _T("/t") ) )
2130         {
2131             if ( ++argn < argc )
2132                 *pdwThreadId = _tcstoul( argv[argn], NULL, 0 );
2133             else
2134                 bSuccess = false;
2135         }
2136         else if ( 0 == _tcsicmp( argv[argn], _T("-noui") ) ||
2137                   0 == _tcsicmp( argv[argn], _T("/noui") ) )
2138         {
2139             g_bNoUserInterface = true;
2140         }
2141         else if ( 0 == _tcsicmp( argv[argn], _T("-send") ) ||
2142                   0 == _tcsicmp( argv[argn], _T("/send") ) )
2143         {
2144             g_bSendReport = true;
2145         }
2146         else if ( 0 == _tcsicmp( argv[argn], _T("-load") ) ||
2147                   0 == _tcsicmp( argv[argn], _T("/load") ) )
2148         {
2149             g_bLoadReport = true;
2150         }
2151         else // treat parameter as image path
2152         {
2153             TCHAR   szImagePath[MAX_PATH];
2154             LPTSTR  lpImageName;
2155 
2156             if ( GetFullPathName( argv[argn], MAX_PATH, szImagePath, &lpImageName ) )
2157             {
2158                 DWORD   dwProcessId = FindProcessForImage( szImagePath );
2159 
2160                 if ( dwProcessId )
2161                     *pdwProcessId = dwProcessId;
2162                 else
2163                     bSuccess = false;
2164             }
2165         }
2166     }
2167 
2168     if ( !*pdwProcessId && !g_bLoadReport )
2169     {
2170         TCHAR   szImagePath[MAX_PATH];
2171         LPTSTR  lpImageName;
2172 
2173         if ( GetFullPathName( TEXT("soffice.exe"), MAX_PATH, szImagePath, &lpImageName ) )
2174         {
2175             DWORD   dwProcessId = FindProcessForImage( szImagePath );
2176 
2177             if ( dwProcessId )
2178                 *pdwProcessId = dwProcessId;
2179             else
2180                 bSuccess = false;
2181         }
2182     }
2183 
2184     return bSuccess;
2185 }
2186 
2187 //***************************************************************************
2188 
2189 BOOL WriteCommentFile( LPCTSTR lpComment )
2190 {
2191     BOOL    fSuccess = FALSE;
2192     TCHAR   szTempPath[MAX_PATH];
2193 
2194     if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
2195     {
2196         TCHAR   szFileName[MAX_PATH];
2197 
2198         if ( GetTempFileName( szTempPath, TEXT("CMT"), 0, szFileName ) )
2199         {
2200             HANDLE  hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2201 
2202             if ( hFile )
2203             {
2204                 DWORD   dwBytesWritten;
2205 
2206                 int needed = WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, NULL, 0, NULL, NULL );
2207                 if ( needed )
2208                 {
2209                     char *lpCommentUTF8 = (char *)alloca( needed );
2210                     WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, lpCommentUTF8, needed, NULL, NULL );
2211                     fSuccess = WriteFile( hFile, lpCommentUTF8, strlen(lpCommentUTF8), &dwBytesWritten, NULL );
2212                 }
2213                 else
2214                     fSuccess = TRUE;
2215 
2216 
2217                 CloseHandle( hFile );
2218 
2219                 WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szCommentFileNameA, MAX_PATH, NULL, NULL );
2220             }
2221 
2222             if ( !fSuccess )
2223                 DeleteFile( szFileName );
2224         }
2225     }
2226 
2227     return fSuccess;
2228 }
2229 
2230 //***************************************************************************
2231 
2232 static int _tsetenv( const _TCHAR *lpVar, const _TCHAR *lpValue )
2233 {
2234     if ( !lpValue )
2235         lpValue = _T("");
2236 
2237     _TCHAR  *envstr = (TCHAR *)alloca( (_tcslen( lpVar ) + _tcslen( lpValue ) + 2) * sizeof(_TCHAR) );
2238 
2239     _tcscpy( envstr, lpVar );
2240     _tcscat( envstr, _T("=") );
2241     _tcscat( envstr, lpValue );
2242 
2243     return _tputenv( envstr );
2244 }
2245 
2246 static bool read_line( FILE *fp, string& rLine )
2247 {
2248     char szBuffer[1024];
2249     bool bSuccess = false;
2250     bool bEOL = false;
2251     string  line;
2252 
2253 
2254     while ( !bEOL && fgets( szBuffer, sizeof(szBuffer), fp ) )
2255     {
2256         int len = strlen(szBuffer);
2257 
2258         bSuccess = true;
2259 
2260         while ( len && szBuffer[len - 1] == '\n' )
2261         {
2262             szBuffer[--len] = 0;
2263             bEOL = true;
2264         }
2265 
2266         line.append( szBuffer );
2267     }
2268 
2269     rLine = line;
2270     return bSuccess;
2271 }
2272 
2273 static string get_script_string( const char *pFileName, const char *pKeyName )
2274 {
2275     FILE    *fp = fopen( pFileName, "rt" );
2276     string  retValue;
2277 
2278     if ( fp )
2279     {
2280         string line;
2281         string section;
2282 
2283         while ( read_line( fp, line ) )
2284         {
2285             line = trim_string( line );
2286 
2287 
2288             string::size_type iEqualSign = line.find( '=', 0 );
2289 
2290             if ( iEqualSign != string::npos )
2291             {
2292                 string  keyname = line.substr( 0, iEqualSign );
2293                 keyname = trim_string( keyname );
2294 
2295                 string  value = line.substr( sal::static_int_cast<string::size_type>(iEqualSign + 1) );
2296                 value = trim_string( value );
2297 
2298                 if ( value.length() && '\"' == value[0] )
2299                 {
2300                     value.erase( 0, 1 );
2301 
2302                     string::size_type iQuotes = value.find( '"', 0 );
2303 
2304                     if ( iQuotes != string::npos )
2305                         value.erase( iQuotes );
2306                 }
2307 
2308                 if ( 0 == stricmp( keyname.c_str(), pKeyName ) )
2309                 {
2310                     retValue = value;
2311                     break;
2312                 }
2313             }
2314         }
2315 
2316         fclose( fp );
2317     }
2318 
2319     return retValue;
2320 }
2321 
2322 static bool ReadBootstrapParams( CrashReportParams &rParams )
2323 {
2324     TCHAR   szBuffer[256] = TEXT("");
2325     TCHAR   szModuleName[MAX_PATH];
2326     TCHAR   szModuleVersionName[MAX_PATH];
2327     TCHAR   szDrive[_MAX_DRIVE];
2328     TCHAR   szDir[_MAX_DIR];
2329     TCHAR   szFName[_MAX_FNAME];
2330     TCHAR   szExt[_MAX_EXT];
2331     TCHAR   szReportServer[MAX_HOSTNAME];
2332     TCHAR   szReportPort[256];
2333     bool    bSuccess = false;
2334 
2335     GetModuleFileName( NULL, szModuleName, MAX_PATH );
2336     _tsplitpath( szModuleName, szDrive, szDir, szFName, szExt );
2337     _tmakepath( szModuleName, szDrive, szDir, _T("bootstrap"), _T(".ini") );
2338     _tmakepath( szModuleVersionName, szDrive, szDir, _T("version"), _T(".ini") );
2339 
2340     if (
2341         GetPrivateProfileString(
2342         TEXT("Bootstrap"),
2343         TEXT("ProductKey"),
2344         TEXT("OpenOffice"),
2345         szBuffer,
2346         elementsof(szBuffer),
2347         szModuleName )
2348         )
2349     {
2350         TCHAR   *pVersion = _tcschr( szBuffer, ' ' );
2351 
2352         g_wstrProductKey = szBuffer;
2353 
2354         if ( pVersion )
2355         {
2356             *pVersion = 0;
2357             pVersion++;
2358         }
2359         else
2360             pVersion = TEXT("");
2361 
2362         if ( !_tgetenv( _T("PRODUCTNAME") ) )
2363         {
2364             _tsetenv( TEXT("PRODUCTNAME"), szBuffer );
2365         }
2366         if ( !_tgetenv( _T("PRODUCTVERSION") ) )
2367             _tsetenv( TEXT("PRODUCTVERSION"), pVersion );
2368     }
2369 
2370     GetPrivateProfileString(
2371         TEXT("Version"),
2372         TEXT("buildid"),
2373         TEXT("unknown"),
2374         g_szBuildId, elementsof(g_szBuildId),
2375         szModuleVersionName );
2376 
2377     g_strDefaultLanguage = get_script_string( "instdb.inf", "DefaultLanguage" );
2378 
2379     if ( GetPrivateProfileString(
2380         TEXT("ErrorReport"),
2381         TEXT("ErrorReportPort"),
2382         TEXT("80"),
2383         szReportPort, elementsof(szReportPort),
2384         szModuleName
2385         ) )
2386     {
2387         TCHAR *endptr = NULL;
2388 
2389         unsigned short uReportPort = (unsigned short)_tcstoul( szReportPort, &endptr, 10 );
2390         if ( uReportPort )
2391             g_uReportPort = uReportPort;
2392     }
2393 
2394     if ( GetPrivateProfileString(
2395         TEXT("ErrorReport"),
2396         TEXT("ErrorReportServer"),
2397         TEXT(""),
2398         szReportServer, elementsof(szReportServer),
2399         szModuleName
2400         ) )
2401     {
2402         bSuccess = 0 != WideCharToMultiByte( CP_ACP, 0, szReportServer, -1, g_szReportServerA, elementsof(g_szReportServerA), NULL, NULL );
2403     }
2404 
2405     LPCTSTR lpEnvString;
2406 
2407     if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYSERVER") )) )
2408         rParams.sProxyServer = lpEnvString;
2409 
2410     if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYPORT") )) )
2411         rParams.sProxyPort = lpEnvString;
2412 
2413     if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_SENDERADDRESS") )) )
2414         rParams.sEmail = lpEnvString;
2415 
2416     return bSuccess;
2417 }
2418 
2419 //***************************************************************************
2420 
2421 bool SendHTTPRequest(
2422                 FILE *fp,
2423                 const char *pszServer,
2424                 unsigned short uPort = 80,
2425                 const char *pszProxyServer = NULL,
2426                 unsigned short uProxyPort = 8080 )
2427 {
2428     bool success = false;
2429 
2430     struct hostent *hp;
2431 
2432     if ( pszProxyServer )
2433         hp = gethostbyname( pszProxyServer );
2434     else
2435         hp = gethostbyname( pszServer );
2436 
2437     if ( hp )
2438     {
2439         SOCKET  s = socket( AF_INET, SOCK_STREAM, 0 );
2440 
2441         if ( s )
2442         {
2443             struct sockaddr_in address;
2444 
2445             memcpy(&(address.sin_addr.s_addr), *(hp->h_addr_list),sizeof(struct in_addr));
2446             address.sin_family = AF_INET;
2447 
2448             if ( pszProxyServer )
2449                 address.sin_port = ntohs( uProxyPort );
2450             else
2451                 address.sin_port = ntohs( uPort );
2452 
2453             if ( 0 == connect( s, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) )
2454             {
2455                 fseek( fp, 0, SEEK_END );
2456                 size_t length = ftell( fp );
2457                 fseek( fp, 0, SEEK_SET );
2458 
2459                 char buffer[2048];
2460 
2461                 if ( pszProxyServer )
2462                     sprintf( buffer,
2463                     "POST http://%s:%d/soap/servlet/rpcrouter HTTP/1.0\r\n"
2464                         "Content-Type: text/xml; charset=\"utf-8\"\r\n"
2465                         "Content-Length: %d\r\n"
2466                         "SOAPAction: \"\"\r\n\r\n",
2467                         pszServer,
2468                         uPort,
2469                         length
2470                         );
2471                 else
2472                     sprintf( buffer,
2473                         "POST /soap/servlet/rpcrouter HTTP/1.0\r\n"
2474                         "Content-Type: text/xml; charset=\"utf-8\"\r\n"
2475                         "Content-Length: %d\r\n"
2476                         "SOAPAction: \"\"\r\n\r\n",
2477                         length
2478                         );
2479 
2480                 if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) )
2481                 {
2482                     size_t nBytes;
2483 
2484                     do
2485                     {
2486                         nBytes = fread( buffer, 1, sizeof(buffer), fp );
2487 
2488                         if ( nBytes )
2489                             success = SOCKET_ERROR != send( s, buffer, nBytes, 0 );
2490                     } while( nBytes && success );
2491 
2492                     if ( success )
2493                     {
2494                         memset( buffer, 0, sizeof(buffer) );
2495                         success = SOCKET_ERROR != recv( s, buffer, sizeof(buffer), 0 );
2496                         if ( success )
2497                         {
2498                             char szHTTPSignature[sizeof(buffer)] = "";
2499                             unsigned uHTTPReturnCode = 0;
2500 
2501                             sscanf( buffer, "%s %d ", szHTTPSignature, &uHTTPReturnCode );
2502                             success = uHTTPReturnCode == 200;
2503                         }
2504                     }
2505                 }
2506 
2507             }
2508 
2509             closesocket( s );
2510         }
2511     }
2512 
2513     return success;
2514 }
2515 
2516 //***************************************************************************
2517 
2518 static void WriteSOAPRequest( FILE *fp )
2519 {
2520     fprintf( fp,
2521         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2522         "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
2523         "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
2524         "xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\"\n"
2525         "xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\n"
2526         "xmlns:rds=\"urn:ReportDataService\"\n"
2527         "xmlns:apache=\"http://xml.apache.org/xml-soap\"\n"
2528         "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
2529         "<SOAP-ENV:Body>\n"
2530         );
2531 
2532     fprintf( fp, "<rds:submitReport>\n" );
2533     fprintf( fp, "<body xsi:type=\"xsd:string\">This is an autogenerated crash report mail.</body>\n" );
2534     fprintf( fp, "<hash xsi:type=\"apache:Map\">\n" );
2535 
2536     FILE    *fpin = fopen( g_szReportFileNameA, "r" );
2537     if ( fpin )
2538     {
2539         fprintf( fp,
2540             "<item>\n"
2541             "<key xsi:type=\"xsd:string\">reportmail.xml</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     fpin = fopen( g_szCommentFileNameA, "r" );
2549     if ( fpin )
2550     {
2551         fprintf( fp,
2552             "<item>\n"
2553             "<key xsi:type=\"xsd:string\">description.txt</key>\n"
2554             "<value xsi:type=\"xsd:string\"><![CDATA[" );
2555         fcopy( fpin, fp );
2556         fprintf( fp, "]]></value></item>\n" );
2557         fclose( fpin );
2558     };
2559 
2560 
2561     fpin = fopen( g_szDumpFileNameA, "rb" );
2562     if ( fpin )
2563     {
2564         FILE *fptemp = _tmpfile();
2565 
2566         if ( fptemp )
2567         {
2568             if ( base64_encode( fpin, fptemp ) )
2569             {
2570                 fseek( fptemp, 0, SEEK_SET );
2571                 fprintf( fp,
2572                     "<item>\n"
2573                     "<key xsi:type=\"xsd:string\">user.dmp</key>\n"
2574                     "<value xsi:type=\"xsd:string\">" );
2575                 fcopy( fptemp, fp );
2576                 fprintf( fp, "</value></item>\n" );
2577             }
2578             fclose( fptemp );
2579         }
2580         fclose( fpin );
2581     }
2582 
2583     fprintf( fp,
2584         "</hash>\n"
2585         "</rds:submitReport>\n"
2586         "</SOAP-ENV:Body>\n"
2587         "</SOAP-ENV:Envelope>\n"
2588         );
2589 }
2590 
2591 //***************************************************************************
2592 
2593 struct RequestParams
2594 {
2595     bool    success;
2596     FILE    *fpin;
2597     const char *lpServer;
2598     unsigned short uPort;
2599     const char *lpProxyServer;
2600     unsigned short uProxyPort;
2601     HWND    hwndStatus;
2602 };
2603 
2604 void _cdecl SendingThread( void *lpArgs )
2605 {
2606     RequestParams *pParams = (RequestParams *)lpArgs;
2607 
2608     pParams->success = SendHTTPRequest( pParams->fpin, pParams->lpServer, pParams->uPort, pParams->lpProxyServer, pParams->uProxyPort );
2609 
2610     PostMessage( pParams->hwndStatus, WM_COMMAND, IDOK, 0 );
2611 }
2612 
2613 //***************************************************************************
2614 
2615 INT_PTR CALLBACK SendingStatusDialogProc(
2616     HWND hwndDlg,
2617     UINT uMsg,
2618     WPARAM wParam,
2619     LPARAM lParam
2620     )
2621 {
2622     static RequestParams *pRequest = NULL;
2623     static HANDLE hSendingThread = NULL;
2624 
2625     switch ( uMsg )
2626     {
2627     case WM_INITDIALOG:
2628         {
2629             TCHAR   szBuffer[1024] = TEXT("");
2630             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr( hwndDlg, GWLP_HINSTANCE );
2631             //HWND  hwndParent = (HWND)GetWindowLongPtr( hwndDlg, GWLP_HWNDPARENT );
2632 
2633             pRequest = (RequestParams *)lParam;
2634 
2635             LoadAndFormatString( hInstance, IDS_SENDING_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
2636             SetWindowText( hwndDlg, szBuffer );
2637 
2638             LoadAndFormatString( hInstance, IDS_SENDING_REPORT_STATUS, szBuffer, elementsof(szBuffer) );
2639             Static_SetText( GetDlgItem(hwndDlg, IDC_SENDING_REPORT_STATUS), szBuffer );
2640 
2641             LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
2642             Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
2643 
2644             pRequest->hwndStatus = hwndDlg;
2645 
2646             hSendingThread = (HANDLE)_beginthread( SendingThread, 0, pRequest );
2647         }
2648         return TRUE;
2649     case WM_COMMAND:
2650         switch ( LOWORD(wParam) )
2651         {
2652         case IDCANCEL:
2653             TerminateThread( hSendingThread, 0 );
2654         case IDOK:
2655             WaitForSingleObject( hSendingThread, INFINITE );
2656             CloseHandle( hSendingThread );
2657             EndDialog( hwndDlg, wParam );
2658             return TRUE;
2659         }
2660         break;
2661     default:
2662         break;
2663     }
2664 
2665     return FALSE;
2666 }
2667 
2668 //***************************************************************************
2669 
2670 bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams )
2671 {
2672     bool success = false;
2673     char szProxyServer[1024] = "";
2674     unsigned short uProxyPort = 8080;
2675     TCHAR *endptr = NULL;
2676 
2677     switch ( rParams.uInternetConnection )
2678     {
2679     case 2:
2680         {
2681             WideCharToMultiByte(
2682                 CP_ACP, 0, rParams.sProxyServer.c_str(), -1,
2683                 szProxyServer, sizeof(szProxyServer), NULL, NULL );
2684             uProxyPort = (unsigned short)_tcstoul( rParams.sProxyPort.c_str(), &endptr, 10 );
2685         }
2686         break;
2687     case 0:
2688         {
2689             DWORD   dwProxyEnable = 0;
2690 
2691             RegReadValue( HKEY_CURRENT_USER,
2692                 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
2693                 TEXT("ProxyEnable"),
2694                 &dwProxyEnable,
2695                 sizeof(dwProxyEnable) );
2696 
2697             if ( dwProxyEnable )
2698             {
2699                 TCHAR   tszProxyServers[1024] = TEXT("");
2700 
2701                 if ( ERROR_SUCCESS == RegReadValue( HKEY_CURRENT_USER,
2702                     TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
2703                     TEXT("ProxyServer"),
2704                     tszProxyServers,
2705                     sizeof(tszProxyServers) ) )
2706                 {
2707                     TCHAR *lpHttpStart = _tcsstr( tszProxyServers, TEXT("http=") );
2708 
2709                     if ( lpHttpStart )
2710                         lpHttpStart += 5;
2711                     else
2712                         lpHttpStart = tszProxyServers;
2713 
2714                     TCHAR *lpHttpEnd = _tcschr( lpHttpStart, ';' );
2715 
2716                     if ( lpHttpEnd )
2717                         *lpHttpEnd = 0;
2718 
2719                     char    szHTTPProxyServer[1024] = "";
2720                     WideCharToMultiByte( CP_ACP, 0, lpHttpStart, -1, szHTTPProxyServer, sizeof(szHTTPProxyServer), NULL, NULL );
2721 
2722                     char *lpColon = strchr( szHTTPProxyServer, ':' );
2723 
2724                     if ( lpColon )
2725                     {
2726                         char *endptr = NULL;
2727 
2728                         *lpColon = 0;
2729                         uProxyPort = (unsigned short)strtoul( lpColon + 1, &endptr, 10 );
2730                     }
2731                     else
2732                         uProxyPort = 8080;
2733 
2734                     strcpy( szProxyServer, szHTTPProxyServer );
2735 
2736                 }
2737             }
2738         }
2739         break;
2740     default:
2741     case 1:
2742         break;
2743     }
2744 
2745     FILE    *fptemp = _tmpfile();
2746     if ( fptemp )
2747     {
2748         RequestParams   request;
2749 
2750         request.success = false;
2751         request.fpin = fptemp;
2752         request.lpServer = REPORT_SERVER;
2753         request.uPort = REPORT_PORT;
2754         request.lpProxyServer = szProxyServer[0] ? szProxyServer : NULL;
2755         request.uProxyPort = uProxyPort;
2756         request.hwndStatus = NULL;
2757 
2758         WriteSOAPRequest( fptemp );
2759         fseek( fptemp, 0, SEEK_SET );
2760 
2761         if ( hwndParent )
2762         {
2763             int retid = DialogBoxParam(
2764                 GetModuleHandle(NULL),
2765                 MAKEINTRESOURCE(IDD_SENDING_STATUS),
2766                 hwndParent,
2767                 SendingStatusDialogProc,
2768                 (LPARAM)&request
2769                 );
2770 
2771             success = request.success;
2772 
2773             if ( IDOK == retid )
2774             {
2775                 if ( !success )
2776                 {
2777                     TCHAR   szMessage[1024];
2778 
2779                     LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
2780 
2781                     MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
2782                 }
2783                 else
2784                 {
2785                     TCHAR   szMessage[1024];
2786                     TCHAR   szTitle[1024];
2787 
2788                     LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
2789                     LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_HEADER, szTitle, elementsof(szTitle) );
2790 
2791                     MessageBox( hwndParent, szMessage, szTitle, MB_ICONINFORMATION | MB_OK );
2792                 }
2793             }
2794 
2795         }
2796         else
2797         {
2798             HANDLE hSendingThread = (HANDLE)_beginthread( SendingThread, 0, (void *)&request );
2799 
2800             WaitForSingleObject( hSendingThread, INFINITE );
2801 
2802             success = request.success;
2803             if ( !success )
2804             {
2805                 TCHAR   szMessage[1024];
2806 
2807                 LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
2808                 _ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
2809             }
2810             else
2811             {
2812                 TCHAR   szMessage[1024];
2813 
2814                 LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
2815 
2816                 _ftprintf( stderr, _T("SUCCESS: %s\n"), szMessage );
2817             }
2818         }
2819         fclose( fptemp );
2820     }
2821     else
2822     {
2823         TCHAR   szMessage[1024];
2824 
2825         LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_DISK_FULL, szMessage, elementsof(szMessage) );
2826 
2827         if ( hwndParent )
2828             MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
2829         else
2830             _ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
2831     }
2832 
2833     return success;
2834 }
2835 
2836 //***************************************************************************
2837 
2838 #ifdef __MINGW32__
2839 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR /*lpCmdLine*/, int )
2840 #else
2841 int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR /*lpCmdLine*/, int )
2842 #endif
2843 {
2844     int exitcode = -1;
2845     int argc = __argc;
2846 
2847 #ifdef __MINGW32__
2848     char **argv = __argv;
2849 #else
2850 #ifdef _UNICODE
2851     char **argv = new char *[argc + 1];
2852 
2853     for ( int argn = 0; argn < argc; argn++ )
2854     {
2855         int nBytes = WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, NULL, 0, NULL, NULL );
2856         argv[argn] = new char[nBytes];
2857         WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, argv[argn], nBytes, NULL, NULL );
2858     }
2859     argv[argc] = NULL;
2860 #else
2861     char **argv = __targv;
2862 #endif
2863 #endif
2864 
2865     osl_setCommandArgs( argc, argv );
2866 
2867     PEXCEPTION_POINTERS pExceptionPointers = NULL;
2868     DWORD               dwProcessId = 0;
2869     DWORD               dwThreadId = 0;
2870 
2871     WSADATA wsaData;
2872     WORD    wVersionRequested;
2873 
2874     wVersionRequested = MAKEWORD(1, 1);
2875     WSAStartup(wVersionRequested, &wsaData);
2876 
2877     CrashReportParams   Params;
2878 
2879     Params.ReadFromRegistry();
2880     Params.ReadFromEnvironment();
2881 
2882     if ( ReadBootstrapParams( Params ) &&
2883         ParseCommandArgs( &dwProcessId, &pExceptionPointers, &dwThreadId ) )
2884     {
2885         bool    bGotDumpFile;
2886 
2887         if ( g_bLoadReport )
2888             bGotDumpFile = FindDumpFile();
2889         else
2890             bGotDumpFile = WriteDumpFile( dwProcessId, pExceptionPointers, dwThreadId );
2891 
2892         if( bGotDumpFile )
2893         {
2894             hash_map< string, string > aLibraries;
2895 
2896             if ( g_bLoadReport )
2897             {
2898                 g_fpStackFile = _open_reportfile( _T(".stk"), _T("rb") );
2899                 g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("rb") );
2900             }
2901             else
2902             {
2903                 if ( g_bSendReport )
2904                 {
2905                     g_fpStackFile = _tmpfile();
2906                     g_fpChecksumFile = _tmpfile();
2907                 }
2908                 else
2909                 {
2910                     g_fpStackFile = _open_reportfile( _T(".stk"), _T("w+b") );
2911                     g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("w+b") );
2912 
2913                     FILE    *fpUnsent = _open_reportfile( _T(".lck"), _T("w+b") );
2914                     if ( fpUnsent )
2915                     {
2916                         fprintf( fpUnsent, "Unsent\r\n" );
2917                         fclose( fpUnsent );
2918                     }
2919                 }
2920 
2921                 WriteStackFile( g_fpStackFile, aLibraries, dwProcessId, pExceptionPointers );
2922                 WriteChecksumFile( g_fpChecksumFile, aLibraries );
2923                 WriteReportFile( &Params );
2924 
2925                 FILE    *fpPreview = _open_reportfile( _T(".prv"), _T("w+b") );
2926 
2927                 if ( fpPreview )
2928                 {
2929                     FILE     *fp = fopen( g_szReportFileNameA, "rb" );
2930                     if ( fp )
2931                     {
2932                         fcopy( fp, fpPreview );
2933                         fclose( fp );
2934                     }
2935                     fclose( fpPreview );
2936                 }
2937             }
2938 
2939             if ( g_bSendReport )
2940             {
2941                 InitCommonControls();
2942 
2943                 // Actually this should never be true anymore
2944                 if ( !g_bNoUserInterface && InitRichEdit() )
2945                 {
2946 
2947                     INT_PTR result = DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG_FRAME), NULL, DialogProc, (LPARAM)&Params );
2948 
2949                     if ( result > 0 )
2950                     {
2951                         exitcode = 0;
2952                     }
2953                     DeinitRichEdit();
2954                 }
2955                 else
2956                 {
2957                     WriteCommentFile( Params.sComment.c_str() );
2958                     WriteReportFile( &Params );
2959                     if ( SendCrashReport( NULL, Params ) )
2960                         exitcode = 0;
2961                 }
2962 
2963 
2964                 if ( g_szReportFileNameA[0] )
2965                     DeleteFileA( g_szReportFileNameA );
2966 
2967                 if ( g_szCommentFileNameA[0] )
2968                     DeleteFileA( g_szCommentFileNameA );
2969             }
2970             else
2971             {
2972                 if ( g_szReportFileNameA[0] )
2973                     DeleteFileA( g_szReportFileNameA );
2974                 exitcode = 0;
2975             }
2976 
2977             if ( g_szDumpFileNameA[0] && g_bSendReport )
2978                     DeleteFileA( g_szDumpFileNameA );
2979 
2980             if ( g_fpStackFile )
2981                 fclose( g_fpStackFile );
2982 
2983             if ( g_fpChecksumFile )
2984                 fclose( g_fpChecksumFile );
2985         }
2986     }
2987 
2988 
2989     return exitcode;
2990 }
2991