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