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