xref: /trunk/main/crashrep/source/win32/soreport.cpp (revision e395a2239405f9a5d0c7e95f212fdcf087aeb3ea)
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( (intptr_t)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( (intptr_t)hFile, _O_TEXT );
670                 FILE    *fp = _fdopen( fd, "w+t" );
671                 CHAR    szTitle[1024] = "";
672                 CHAR    szBuildId[1024] = "";
673                 CHAR    szEmail[1024] = "";
674                 const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
675 
676                 WideCharToMultiByte( CP_UTF8, 0, pParams->sTitle.c_str(), -1, szTitle, sizeof(szTitle), NULL, NULL );
677                 WideCharToMultiByte( CP_UTF8, 0, g_szBuildId, -1, szBuildId, sizeof(szBuildId), NULL, NULL );
678                 WideCharToMultiByte( CP_UTF8, 0, pParams->sEmail.c_str(), -1, szEmail, sizeof(szEmail), NULL, NULL );
679 
680                 fprintf( fp,
681                     "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
682                     "<!DOCTYPE errormail:errormail PUBLIC \"-//OpenOffice.org//DTD ErrorMail 1.0//EN\" \"errormail.dtd\">\n"
683                     "<errormail:errormail xmlns:errormail=\"http://openoffice.org/2002/errormail\" usertype=\"%s\">\n"
684                     "<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.1\" feedback=\"%s\" email=\"%s\">\n",
685                     pszUserType ? pszUserType : "",
686                     pParams->fAllowContact ? "true" : "false",
687                     pParams->fAllowContact ? xml_encode(szEmail).c_str() : ""
688                     );
689 
690                 fprintf( fp,
691                     "<reportmail:title>%s</reportmail:title>\n",
692                     xml_encode(szTitle).c_str() );
693 
694                 fprintf( fp,
695                     "<reportmail:attachment name=\"description.txt\" media-type=\"text/plain;charset=UTF-8\" class=\"UserComment\"/>\n"
696                     "<reportmail:attachment name=\"user.dmp\" media-type=\"application/octet-stream\" class=\"UserDump\"/>\n"
697                     "</reportmail:mail>\n"
698 
699                     "<officeinfo:officeinfo xmlns:officeinfo=\"http://openoffice.org/2002/officeinfo\" build=\"%s\" platform=\"%s\" language=\"%s\" procpath=\"%s\" exceptiontype=\"0x%08X\" product=\"%s\"/>\n",
700                     szBuildId,
701                     _INPATH,
702                     xml_encode(g_strDefaultLanguage).c_str(),
703                     xml_encode(GetModuleDirectory( NULL )).c_str(),
704                     g_dwExceptionCode,
705                     xml_encode(wstring2utf8(g_wstrProductKey)).c_str()
706                     );
707 
708                 OSVERSIONINFO   VersionInfo;
709 
710                 ZeroMemory( &VersionInfo, sizeof(VersionInfo) );
711                 VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo );
712 
713                 GetVersionEx( &VersionInfo );
714 
715                 fprintf( fp,
716                     "<systeminfo:systeminfo xmlns:systeminfo=\"http://openoffice.org/2002/systeminfo\">\n"
717                     "<systeminfo:System name=\"%s\" version=\"%d.%d\" build=\"%d\" locale=\"0x%08x\"/>\n"
718                     ,
719                     VER_PLATFORM_WIN32_NT == VersionInfo.dwPlatformId ? "Windows NT" : "Windows",
720                     VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion,
721                     VersionInfo.dwBuildNumber,
722                     GetUserDefaultLangID()
723 
724                     );
725                 fprintf( fp, "<systeminfo:CPU type=\"x86\"/>\n" );
726                 fprintf( fp, "</systeminfo:systeminfo>\n" );
727 
728                 fseek( g_fpStackFile, 0, SEEK_SET );
729                 fcopy( g_fpStackFile, fp );
730 
731                 fseek( g_fpChecksumFile, 0, SEEK_SET );
732                 fcopy( g_fpChecksumFile, fp );
733 
734                 fprintf( fp, "</errormail:errormail>\n" );
735 
736                 fclose( fp );
737 
738                 fSuccess = TRUE;
739 
740                 WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szReportFileNameA, MAX_PATH, NULL, NULL );
741             }
742 
743             if ( !fSuccess )
744                 DeleteFile( szFileName );
745         }
746     }
747 
748     return fSuccess;
749 }
750 
751 //***************************************************************************
752 
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 INT_PTR CALLBACK PreviewDialogProc(
862     HWND hwndDlg,
863     UINT uMsg,
864     WPARAM wParam,
865     LPARAM lParam
866     )
867 {
868     static RECT rcClient;
869 
870     switch ( uMsg )
871     {
872     case WM_SIZE:
873         {
874         LONG    cx = LOWORD( lParam );
875         LONG    cy = HIWORD( lParam );
876         LONG    dxClient, dyClient;
877 
878         dxClient = cx - rcClient.right;
879         dyClient = cy - rcClient.bottom;
880 
881         EnumChildWindows( hwndDlg, GrowChildWindows, MAKELONG( (SHORT)dxClient, (SHORT)dyClient) );
882 
883         GetClientRect( hwndDlg, &rcClient );
884         }
885         break;
886     case WM_INITDIALOG:
887         {
888             GetClientRect( hwndDlg, &rcClient );
889             SetGrowMode( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GM_HIX | GM_HIY );
890             SetGrowMode( GetDlgItem(hwndDlg, IDOK), GM_LOX | GM_HIX | GM_LOY | GM_HIY );
891 
892             CrashReportParams *pParams = (CrashReportParams *)lParam;
893 
894             TCHAR   szBuffer[256] = TEXT("");
895             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr( hwndDlg, GWLP_HINSTANCE );
896             HWND    hwndParent = (HWND)GetWindowLongPtr( hwndDlg, GWLP_HWNDPARENT );
897 
898             GetWindowText( hwndParent, szBuffer, elementsof(szBuffer) );
899             SetWindowText( hwndDlg, szBuffer );
900 
901             LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) );
902             Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer );
903 
904             basic_string<TCHAR> aString;
905 
906             aString.append( pParams->sTitle );
907             aString.append( _T("\r\n\r\n") );
908             aString.append( pParams->sComment );
909             aString.append( _T("\r\n---------- report ----------\r\n") );
910 
911             FILE    *fp = fopen( g_szReportFileNameA, "r" );
912 
913             if ( fp )
914             {
915                 char    buf[1024];
916 
917                 while ( fgets( buf, elementsof(buf), fp ) != NULL )
918                 {
919                     WCHAR   bufW[1024];
920 
921                     MultiByteToWideChar( CP_UTF8, 0, buf, -1, bufW, elementsof(bufW) );
922 
923                     aString.append( bufW );
924                 }
925 
926                 fclose( fp );
927             }
928 
929             aString.append( _T("\r\n---------- stack ----------\r\n") );
930 
931             fp = fopen( g_szDumpFileNameA, "rb" );
932 
933             if ( fp )
934             {
935                 unsigned char   buf[16];
936                 int     count;
937 
938                 do
939                 {
940                     int i;
941 
942                     count = fread( buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), fp );
943 
944                     for ( i = 0; i < count; i++ )
945                     {
946                         TCHAR   output[16];
947 
948                         _sntprintf( output, elementsof(output), _T("%02X\x20"), buf[i] );
949                         aString.append( output );
950                     }
951                     for ( ; i < elementsof(buf); i++ )
952                     {
953                         aString.append( _T("\x20\x20\x20") );
954                     }
955 
956                     for ( i = 0; i < count; i++ )
957                     {
958                         TCHAR   output[2];
959 
960                         if ( (int)buf[i] >= 0x20 && (int)buf[i] <= 0x7F )
961                             output[0] = (TCHAR)buf[i];
962                         else
963                             output[0] = '.';
964                         output[1] = 0;
965                         aString.append( output );
966                     }
967 
968                     aString.append( _T("\r\n") );
969 
970                 } while ( count );
971 
972                 fclose( fp );
973             }
974 
975             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), aString.c_str() );
976 
977 
978             SetWindowFont( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GetStockObject( SYSTEM_FIXED_FONT ), TRUE );
979         }
980         return TRUE;
981     case WM_COMMAND:
982         switch ( LOWORD(wParam) )
983         {
984         case IDOK:
985         case IDCANCEL:
986             EndDialog( hwndDlg, wParam );
987             return TRUE;
988         }
989         break;
990     default:
991         break;
992     }
993 
994     return FALSE;
995 }
996 //***************************************************************************
997 
PreviewReport(HWND hwndParent,CrashReportParams * pParams)998 static void PreviewReport( HWND hwndParent, CrashReportParams *pParams )
999 {
1000     HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndParent, GWLP_HINSTANCE );
1001 
1002     WriteReportFile( pParams );
1003 
1004     DialogBoxParam(
1005         hInstance,
1006         MAKEINTRESOURCE(IDD_PREVIEW_FRAME),
1007         hwndParent,
1008         PreviewDialogProc,
1009         (LPARAM)pParams
1010         );
1011 
1012     DeleteFileA( g_szReportFileNameA );
1013 }
1014 //***************************************************************************
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 INT_PTR CALLBACK OptionsDialogProc(
1032     HWND hwndDlg,
1033     UINT uMsg,
1034     WPARAM wParam,
1035     LPARAM lParam
1036     )
1037 {
1038     static CrashReportParams *pParams;
1039 
1040     switch ( uMsg )
1041     {
1042     case WM_INITDIALOG:
1043         {
1044             TCHAR   szBuffer[1024] = TEXT("");
1045             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr( hwndDlg, GWLP_HINSTANCE );
1046             //HWND  hwndParent = (HWND)GetWindowLongPtr( hwndDlg, GWLP_HWNDPARENT );
1047 
1048             pParams = (CrashReportParams *)lParam;
1049 
1050             LoadAndFormatString( hInstance, IDS_OPTIONS_CAPTION, szBuffer, elementsof(szBuffer) );
1051             SetWindowText( hwndDlg, szBuffer );
1052 
1053             LoadAndFormatString( hInstance, IDS_PROXY_SETTINGS_HEADER, szBuffer, elementsof(szBuffer) );
1054             Static_SetText( GetDlgItem(hwndDlg, IDC_PROXY_SETTINGS), szBuffer );
1055 
1056             LoadAndFormatString( hInstance, IDS_PROXY_SYSTEM, szBuffer, elementsof(szBuffer) );
1057             Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM), szBuffer );
1058 
1059             LoadAndFormatString( hInstance, IDS_PROXY_DIRECT, szBuffer, elementsof(szBuffer) );
1060             Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT), szBuffer );
1061 
1062             LoadAndFormatString( hInstance, IDS_PROXY_MANUAL, szBuffer, elementsof(szBuffer) );
1063             Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL), szBuffer );
1064 
1065             LoadAndFormatString( hInstance, IDS_LABEL_PROXYSERVER, szBuffer, elementsof(szBuffer) );
1066             Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYSERVER), szBuffer );
1067 
1068             LoadAndFormatString( hInstance, IDS_LABEL_PROXYPORT, szBuffer, elementsof(szBuffer) );
1069             Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYPORT), szBuffer );
1070 
1071             LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) );
1072             Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer );
1073 
1074             LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
1075             Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
1076 
1077             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), pParams->sProxyServer.c_str() );
1078             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), pParams->sProxyPort.c_str() );
1079 
1080             Button_SetCheck( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM + pParams->uInternetConnection), BST_CHECKED );
1081 
1082             SendMessage(
1083                 GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION),
1084                 EM_SETBKGNDCOLOR,
1085                 (WPARAM)FALSE,
1086                 GetSysColor( COLOR_3DFACE ) );
1087             LoadAndFormatString( hInstance, IDS_PROXY_DESCRIPTION, szBuffer, elementsof(szBuffer) );
1088             Edit_SetText( GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION), szBuffer );
1089 
1090             UpdateOptionsDialogControls( hwndDlg );
1091         }
1092         return TRUE;
1093     case WM_COMMAND:
1094         switch ( LOWORD(wParam) )
1095         {
1096         case IDC_RADIO_SYSTEM:
1097         case IDC_RADIO_DIRECT:
1098         case IDC_RADIO_MANUAL:
1099             if ( BN_CLICKED == HIWORD(wParam) )
1100                 UpdateOptionsDialogControls( hwndDlg );
1101             break;
1102         case IDOK:
1103             {
1104             TCHAR szBuffer[1024];
1105 
1106             Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), szBuffer, elementsof(szBuffer) );
1107             pParams->sProxyServer = szBuffer;
1108 
1109             Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), szBuffer, elementsof(szBuffer) );
1110             pParams->sProxyPort = szBuffer;
1111 
1112             if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT) ) & BST_CHECKED )
1113                 pParams->uInternetConnection = 1;
1114             else if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED )
1115                 pParams->uInternetConnection = 2;
1116             else
1117                 pParams->uInternetConnection = 0;
1118             }
1119         case IDCANCEL:
1120             EndDialog( hwndDlg, wParam );
1121             return TRUE;
1122         }
1123         break;
1124     default:
1125         break;
1126     }
1127 
1128     return FALSE;
1129 }
1130 
1131 //***************************************************************************
1132 
OptionsDialog(HWND hwndParent,CrashReportParams * pParams)1133 static void OptionsDialog( HWND hwndParent, CrashReportParams *pParams )
1134 {
1135     HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndParent, GWLP_HINSTANCE );
1136 
1137     if ( IDOK == DialogBoxParam(
1138         hInstance,
1139         MAKEINTRESOURCE(IDD_OPTIONS_FRAME),
1140         hwndParent,
1141         OptionsDialogProc,
1142         (LPARAM)pParams
1143         ) )
1144         pParams->WriteToRegistry();
1145 
1146 }
1147 //***************************************************************************
1148 
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 INT_PTR CALLBACK ReportDialogProc(
1162     HWND hwndDlg,
1163     UINT uMsg,
1164     WPARAM wParam,
1165     LPARAM
1166     )
1167 {
1168     switch ( uMsg )
1169     {
1170     case WM_INITDIALOG:
1171         {
1172             CrashReportParams   *pParams = (CrashReportParams*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_USERDATA );
1173             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1174             TCHAR       szBuffer[FORMATBUFSIZE];
1175 
1176             LoadAndFormatString( hInstance, IDS_REPORT_INTRO, szBuffer, elementsof(szBuffer) );
1177             Static_SetText( GetDlgItem(hwndDlg, IDC_REPORT_INTRO), szBuffer );
1178 
1179             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT3), szBuffer );
1180 
1181             LoadAndFormatString( hInstance, IDS_ENTER_TITLE, szBuffer, elementsof(szBuffer) );
1182             Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_TITLE), szBuffer );
1183 
1184             LoadAndFormatString( hInstance, IDS_ENTER_DESCRIPTION, szBuffer, elementsof(szBuffer) );
1185             Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_DESCRIPTION), szBuffer );
1186 
1187             LoadAndFormatString( hInstance, IDS_SHOW_REPORT_BUTTON, szBuffer, elementsof(szBuffer) );
1188             Button_SetText( GetDlgItem(hwndDlg, IDC_SHOW_REPORT), szBuffer );
1189 
1190             LoadAndFormatString( hInstance, IDS_SAVE_REPORT_BUTTON, szBuffer, elementsof(szBuffer) );
1191             Button_SetText( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), szBuffer );
1192 
1193             const char *pszUserType = getenv( "STAROFFICE_USERTYPE" );
1194             if ( pszUserType )
1195                 ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_SHOW );
1196             else
1197                 ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_HIDE );
1198 
1199             LoadAndFormatString( hInstance, IDS_OPTIONS_BUTTON, szBuffer, elementsof(szBuffer) );
1200             Button_SetText( GetDlgItem(hwndDlg, IDC_OPTIONS), szBuffer );
1201 
1202             LoadAndFormatString( hInstance, IDS_ALLOW_CONTACT, szBuffer, elementsof(szBuffer) );
1203             Button_SetText( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), szBuffer );
1204             Button_SetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), pParams->fAllowContact ? BST_CHECKED : BST_UNCHECKED );
1205 
1206             LoadAndFormatString( hInstance, IDS_LABEL_EMAIL, szBuffer, elementsof(szBuffer) );
1207             Button_SetText( GetDlgItem(hwndDlg, IDC_LABEL_EMAIL), szBuffer );
1208 
1209             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), pParams->sEmail.c_str() );
1210 
1211             UpdateReportDialogControls( hwndDlg );
1212         }
1213         return TRUE;
1214     case WM_SHOWWINDOW:
1215         if ( (BOOL)wParam )
1216         {
1217             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1218             CrashReportParams   *pParams = (CrashReportParams*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_USERDATA );
1219             TCHAR       szBuffer[FORMATBUFSIZE];
1220 
1221             LoadAndFormatString( hInstance, IDS_REPORT_CAPTION, szBuffer, elementsof(szBuffer) );
1222             SetWindowText( GetParent(hwndDlg), szBuffer );
1223 
1224             LoadAndFormatString( hInstance, IDS_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
1225             SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer );
1226 
1227             LoadAndFormatString( hInstance, IDS_DONOT_SEND_BUTTON, szBuffer, elementsof(szBuffer) );
1228             Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer );
1229 
1230 
1231             ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), TRUE );
1232             ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), TRUE );
1233             ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), FALSE );
1234 
1235             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), pParams->sTitle.c_str() );
1236             Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), pParams->sComment.c_str() );
1237 
1238             /*
1239             SetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWLP_STYLE,
1240                 GetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWLP_STYLE) | BS_DEFPUSHBUTTON );
1241             SetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDBACK), GWLP_STYLE,
1242                 GetWindowLongPtr( GetDlgItem(GetParent(hwndDlg),IDBACK), GWLP_STYLE) &~ BS_DEFPUSHBUTTON );
1243                 */
1244             SetFocus( GetDlgItem(hwndDlg,IDC_EDIT_TITLE) );
1245         }
1246         break;
1247     case WM_COMMAND:
1248         switch ( LOWORD(wParam) )
1249         {
1250         case IDC_SHOW_REPORT:
1251             {
1252                 TCHAR   szBuffer[32767];
1253 
1254                 CrashReportParams   *pParams = (CrashReportParams*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_USERDATA );
1255 
1256                 pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT) ) ? TRUE : FALSE;
1257 
1258                 Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) );
1259                 pParams->sTitle = szBuffer;
1260 
1261                 Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) );
1262                 pParams->sComment = szBuffer;
1263 
1264                 Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) );
1265                 pParams->sEmail = szBuffer;
1266 
1267                 PreviewReport( GetParent(hwndDlg), pParams );
1268             }
1269             return TRUE;
1270         case IDC_SAVE_REPORT:
1271             SaveDumpFile( GetParent(hwndDlg) );
1272             return TRUE;
1273         case IDC_OPTIONS:
1274             {
1275                 CrashReportParams   *pParams = (CrashReportParams*)GetWindowLongPtr( GetParent(hwndDlg), GWLP_USERDATA );
1276                 OptionsDialog( GetParent(hwndDlg), pParams );
1277             }
1278             return TRUE;
1279         case IDC_ALLOW_CONTACT:
1280             if ( BN_CLICKED == HIWORD(wParam) )
1281                 UpdateReportDialogControls( hwndDlg );
1282             return TRUE;
1283         }
1284         break;
1285     default:
1286         break;
1287     }
1288 
1289     return FALSE;
1290 }
1291 //***************************************************************************
1292 
WelcomeDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)1293 INT_PTR CALLBACK WelcomeDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
1294 {
1295     switch ( uMsg )
1296     {
1297     case WM_INITDIALOG:
1298         {
1299             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1300             HWND    hwndRichEdit = GetDlgItem(hwndDlg, IDC_RICHEDIT21);
1301             TCHAR   szBuffer[FORMATBUFSIZE];
1302             TCHAR   szBuffer2[FORMATBUFSIZE];
1303             TCHAR   szURL[256];
1304             TCHAR   szCaption[256];
1305 
1306             SendMessage(
1307                 hwndRichEdit,
1308                 EM_SETBKGNDCOLOR,
1309                 (WPARAM)FALSE,
1310                 GetSysColor( COLOR_3DFACE ) );
1311 
1312             SendMessage( hwndRichEdit, EM_SETEVENTMASK, 0, ENM_LINK );
1313             SendMessage( hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0 );
1314 
1315             LoadAndFormatString( hInstance, IDS_WELCOME_BODY1, szBuffer, elementsof(szBuffer) );
1316             LoadAndFormatString( hInstance, IDS_WELCOME_BODY2, szBuffer2, elementsof(szBuffer2) );
1317             _tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) );
1318             LoadAndFormatString( hInstance, IDS_WELCOME_BODY3, szBuffer2, elementsof(szBuffer2) );
1319             _tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) );
1320             LoadString( hInstance, IDS_PRIVACY_URL, szURL, elementsof(szURL) );
1321             _tcsncat( szBuffer, szURL, elementsof(szBuffer) );
1322             SetWindowText( hwndRichEdit, szBuffer );
1323 
1324             LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szCaption, elementsof(szCaption) );
1325             SetWindowText( GetParent(hwndDlg), szCaption );
1326 
1327         }
1328         return TRUE;
1329     case WM_SHOWWINDOW:
1330         if ( (BOOL)wParam )
1331         {
1332             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1333             TCHAR       szBuffer[FORMATBUFSIZE];
1334 
1335             LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szBuffer, elementsof(szBuffer) );
1336             SetWindowText( GetParent(hwndDlg), szBuffer );
1337 
1338             LoadAndFormatString( hInstance, IDS_WELCOME_HEADER, szBuffer, elementsof(szBuffer) );
1339             SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer );
1340 
1341             LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
1342             Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer );
1343 
1344             ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), FALSE );
1345             ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), FALSE );
1346             ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), TRUE );
1347 
1348             SetFocus( GetDlgItem(GetParent(hwndDlg),IDNEXT) );
1349         }
1350         break;
1351     case WM_NOTIFY:
1352         {
1353             LPNMHDR pnmh = (LPNMHDR)lParam;
1354 
1355             if ( pnmh->idFrom == IDC_RICHEDIT21 && pnmh->code == EN_LINK )
1356             {
1357                 ENLINK  *plink = (ENLINK*)lParam;
1358 
1359                 if ( plink->msg == WM_LBUTTONUP )
1360                 {
1361                     TCHAR   szBuffer[256];
1362                     TEXTRANGE   range;
1363 
1364                     range.chrg = plink->chrg;
1365                     range.lpstrText = szBuffer;
1366 
1367                     SendMessage( pnmh->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&range );
1368 
1369                     ShellExecute( hwndDlg, NULL, szBuffer, NULL, NULL, SW_SHOWDEFAULT );
1370                 }
1371 
1372             }
1373         }
1374         break;
1375     default:
1376         break;
1377     }
1378 
1379     return FALSE;
1380 }
1381 //***************************************************************************
1382 
DialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)1383 INT_PTR CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
1384 {
1385     static  HWND    hwndPages[2] = { NULL };
1386     static  int     iActualPage = 0;
1387 
1388     switch ( uMsg )
1389     {
1390     case WM_INITDIALOG:
1391         {
1392             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr(hwndDlg, GWLP_HINSTANCE );
1393             TCHAR       szBuffer[FORMATBUFSIZE];
1394 
1395             SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG)lParam );
1396             hwndPages[0] = CreateDialog(
1397                 hInstance,
1398                 MAKEINTRESOURCE(IDD_WELCOME_PAGE),
1399                 hwndDlg,
1400                 WelcomeDialogProc );
1401 
1402             hwndPages[1] = CreateDialog(
1403                 hInstance,
1404                 MAKEINTRESOURCE(IDD_REPORT_PAGE),
1405                 hwndDlg,
1406                 ReportDialogProc );
1407 
1408             CHARFORMAT  chfmt;
1409 
1410             chfmt.cbSize = sizeof(chfmt);
1411             chfmt.dwMask = CFM_BOLD;
1412             chfmt.dwEffects = CFE_BOLD;
1413 
1414             SendMessage(
1415                 GetDlgItem(hwndDlg, IDC_HEADER),
1416                 EM_SETCHARFORMAT,
1417                 SCF_ALL,
1418                 (LPARAM)&chfmt );
1419 
1420             LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
1421             Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
1422 
1423             LoadAndFormatString( hInstance, IDS_NEXT_BUTTON, szBuffer, elementsof(szBuffer) );
1424             Button_SetText( GetDlgItem(hwndDlg, IDNEXT), szBuffer );
1425 
1426             LoadAndFormatString( hInstance, IDS_SEND_BUTTON, szBuffer, elementsof(szBuffer) );
1427             Button_SetText( GetDlgItem(hwndDlg, IDFINISH), szBuffer );
1428 
1429             LoadAndFormatString( hInstance, IDS_BACK_BUTTON, szBuffer, elementsof(szBuffer) );
1430             Button_SetText( GetDlgItem(hwndDlg, IDBACK), szBuffer );
1431 
1432             ShowWindow( hwndPages[1], SW_HIDE );
1433             ShowWindow( hwndPages[0], SW_SHOW );
1434 
1435             // Let Crash Reporter window stay on top of all other windows
1436             SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
1437         }
1438         return FALSE;
1439     case WM_CTLCOLORSTATIC:
1440         return (BOOL)CreateSolidBrush(GetSysColor(COLOR_WINDOW));
1441     case WM_COMMAND:
1442         switch ( LOWORD(wParam) )
1443         {
1444         case IDBACK:
1445             if ( iActualPage > 0 )
1446             {
1447                 ShowWindow( hwndPages[iActualPage], SW_HIDE );
1448                 ShowWindow( hwndPages[--iActualPage], SW_SHOW );
1449             }
1450             return TRUE;
1451         case IDNEXT:
1452             if ( iActualPage < elementsof(hwndPages) - 1 )
1453             {
1454                 ShowWindow( hwndPages[iActualPage], SW_HIDE );
1455                 ShowWindow( hwndPages[++iActualPage], SW_SHOW );
1456             }
1457             return TRUE;
1458         case IDFINISH:
1459             {
1460                 TCHAR   szBuffer[32767];
1461                 CrashReportParams   *pParams = (CrashReportParams*)GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
1462 
1463                 pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndPages[1], IDC_ALLOW_CONTACT) ) ? TRUE : FALSE;
1464 
1465                 Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) );
1466                 pParams->sTitle = szBuffer;
1467 
1468                 Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) );
1469                 pParams->sComment = szBuffer;
1470 
1471                 Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) );
1472                 pParams->sEmail = szBuffer;
1473 
1474                 if ( pParams->fAllowContact && !pParams->sEmail.length() )
1475                 {
1476                     TCHAR   szMessage[MAX_TEXT_BUFFER];
1477 
1478                     LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_NOEMAILADDRESS, szMessage, elementsof(szMessage) );
1479 
1480                     MessageBox( hwndDlg, szMessage, NULL, MB_ICONERROR | MB_OK );
1481                     break; // Don't end the dialog
1482                 }
1483                 else
1484                 {
1485                     pParams->WriteToRegistry();
1486 
1487                     WriteCommentFile( pParams->sComment.c_str() );
1488                     WriteReportFile( pParams );
1489 
1490                     if ( !SendCrashReport( hwndDlg, *pParams ) )
1491                         break; // Don't end the dialog
1492                 }
1493             }
1494             // Fallthrough !!!
1495         case IDCANCEL:
1496             EndDialog( hwndDlg, wParam );
1497             return TRUE;
1498         }
1499         break;
1500     default:
1501         break;
1502     }
1503 
1504     return FALSE;
1505 }
1506 
1507 
1508 
1509 //*****************************************************************************
1510 //* Generate MD5 checksum
1511 //*****************************************************************************
1512 
1513 #define MAGIC_DESCRIPTION_FILLER    'x'
1514 #define MAGIC_DESCRIPTION_COUNT     80
1515 
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 #if defined(INTEL)
1729             frame.AddrPC.Offset = aContextRecord.Eip;
1730 #elif defined(X86_64)
1731             frame.AddrPC.Offset = aContextRecord.Rip;
1732 #else
1733 #error Unsupported architecture
1734 #endif
1735             frame.AddrPC.Mode = AddrModeFlat;
1736 #if defined(INTEL)
1737             frame.AddrFrame.Offset = aContextRecord.Ebp;
1738 #elif defined(X86_64)
1739             frame.AddrFrame.Offset = aContextRecord.Rbp;
1740 #else
1741 #error Unsupported architecture
1742 #endif
1743             frame.AddrFrame.Mode = AddrModeFlat;
1744 
1745             BOOL bSuccess;
1746             int frameNum = 0;
1747 
1748             SymInitialize( hProcess, NULL, TRUE );
1749 
1750             fprintf( fout, "<errormail:Stack type=\"Win32\">\n" );
1751 
1752             do
1753             {
1754                 fSuccess = true;
1755 
1756                 bSuccess = StackWalk( IMAGE_FILE_MACHINE_I386,
1757                     hProcess,
1758                     NULL,
1759                     &frame,
1760                     &aContextRecord,
1761                     (PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory,
1762                     SymFunctionTableAccess,
1763                     SymGetModuleBase,
1764                     NULL );
1765 
1766                 if ( bSuccess )
1767                 {
1768                     // Note: ImageHelp ANSI functions do not have an A postfix while
1769                     //       Unicode versions have a W postfix. There's no macro
1770                     //       that depends on define UNICODE
1771 
1772                     IMAGEHLP_MODULE moduleInfo;
1773 
1774                     ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
1775                     moduleInfo.SizeOfStruct = sizeof(moduleInfo);
1776 
1777                     if ( SymGetModuleInfo( hProcess, frame.AddrPC.Offset, &moduleInfo ) )
1778                     {
1779                         rLibraries[ GetFileName( moduleInfo.LoadedImageName ).c_str() ] = moduleInfo.LoadedImageName;
1780 
1781                         // SymGetSymFromAddr's displacement parameter is arch-dependent:
1782                         // on x86 it is PDWORD, on x64 the dbghelp macro maps it to
1783                         // SymGetSymFromAddr64 wanting PDWORD64.  Match the type per arch
1784                         // (same INTEL/X86_64 guard used for AddrPC.Offset above); an
1785                         // unconditional DWORD64 breaks the x86 build (C2664).
1786 #if defined(INTEL)
1787                         DWORD   dwRelOffset = 0;
1788 #elif defined(X86_64)
1789                         DWORD64 dwRelOffset = 0;
1790 #else
1791 #error Unsupported architecture
1792 #endif
1793                         BYTE    symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 256 ];
1794                         PIMAGEHLP_SYMBOL    pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer;
1795 
1796                         ZeroMemory( symbolBuffer, sizeof(symbolBuffer) );
1797                         pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
1798                         pSymbol->MaxNameLength = 256;
1799 
1800                         if ( SymGetSymFromAddr( hProcess, frame.AddrPC.Offset, &dwRelOffset, pSymbol ) )
1801                             fprintf( fout, "<errormail:StackInfo " \
1802                                 "pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" ordinal=\"%s+0x%p\" name=\"%s\" path=\"%s\"/>\n",
1803                                 frameNum,
1804                                 frame.AddrPC.Offset,
1805                                 frame.AddrPC.Offset - moduleInfo.BaseOfImage,
1806                                 xml_encode(pSymbol->Name).c_str(),
1807                                 frame.AddrPC.Offset - pSymbol->Address,
1808                                 xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
1809                                 xml_encode( GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
1810                                 );
1811                         else
1812                             fprintf( fout, "<errormail:StackInfo " \
1813                                 "pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" name=\"%s\" path=\"%s\"/>\n",
1814                                 frameNum,
1815                                 frame.AddrPC.Offset,
1816                                 frame.AddrPC.Offset - moduleInfo.BaseOfImage,
1817                                 xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(),
1818                                 xml_encode(GetFileDirectory( moduleInfo.LoadedImageName )).c_str()
1819                                 );
1820                     }
1821                     else
1822                         fprintf( fout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%p\"/>\n",
1823                             frameNum,
1824                             frame.AddrPC.Offset
1825                             );
1826 
1827                     frameNum++;
1828                 }
1829 
1830             } while ( bSuccess );
1831 
1832             fprintf( fout, "</errormail:Stack>\n" );
1833 
1834             SymCleanup( hProcess );
1835 
1836             CloseHandle( hProcess );
1837         }
1838 
1839     }
1840 
1841     return fSuccess;
1842 }
1843 
WriteChecksumFile(FILE * fchksum,const hash_map<string,string> & rLibraries)1844 bool WriteChecksumFile( FILE *fchksum, const hash_map< string, string >& rLibraries )
1845 {
1846     bool success = false;
1847 
1848     if ( fchksum && rLibraries.size() )
1849     {
1850         fprintf( fchksum, "<errormail:Checksums type=\"MD5\">\n" );
1851 
1852         hash_map< string, string >::const_iterator iter;
1853 
1854         for ( iter = rLibraries.begin();
1855             iter != rLibraries.end();
1856             iter++ )
1857         {
1858             sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5];
1859             sal_uInt32 nBytesProcessed = calc_md5_checksum(
1860                 iter->second.c_str(),
1861                 checksum, sizeof(checksum) );
1862 
1863             if ( nBytesProcessed )
1864             {
1865                 fprintf( fchksum, "<errormail:Checksum sum=\"0x" );
1866                 for ( int i = 0; i < sizeof(checksum); fprintf( fchksum, "%02X", checksum[i++] ) );
1867                 fprintf( fchksum, "\" bytes=\"%d\" file=\"%s\"/>\n",
1868                     nBytesProcessed,
1869                     GetFileName( iter->first ).c_str() );
1870             }
1871         }
1872 
1873         fprintf( fchksum, "</errormail:Checksums>\n" );
1874 
1875         success = true;
1876     }
1877 
1878     return success;
1879 }
1880 
1881 //***************************************************************************
1882 
FindDumpFile()1883 BOOL FindDumpFile()
1884 {
1885     TCHAR   szFileName[MAX_PATH];
1886 
1887     if ( GetCrashDataPath( szFileName ) )
1888     {
1889         _tcscat( szFileName, _T("\\crashdat.dmp") );
1890 
1891         HANDLE  hFile = CreateFile(
1892             szFileName,
1893             GENERIC_READ,
1894             0, NULL,
1895             OPEN_EXISTING,
1896             FILE_ATTRIBUTE_NORMAL, NULL );
1897 
1898         if ( hFile )
1899         {
1900             CloseHandle( hFile );
1901 
1902             WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
1903             _tcscpy( g_szDumpFileName, szFileName );
1904 
1905             return TRUE;
1906         }
1907     }
1908 
1909     return FALSE;
1910 }
1911 
WriteDumpFile(DWORD dwProcessId,PEXCEPTION_POINTERS pExceptionPointers,DWORD dwThreadId)1912 BOOL WriteDumpFile( DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers, DWORD dwThreadId )
1913 {
1914     BOOL    fSuccess = FALSE;
1915     PMINIDUMP_EXCEPTION_INFORMATION lpExceptionParam = NULL;
1916     MINIDUMP_EXCEPTION_INFORMATION  ExceptionParam;
1917 
1918     HMODULE hDbgHelp = LoadLibrary( _T("DBGHELP.DLL" ) );
1919     MiniDumpWriteDump_PROC  pMiniDumpWriteDump = NULL;
1920 
1921     if ( hDbgHelp )
1922     {
1923         pMiniDumpWriteDump = (MiniDumpWriteDump_PROC)GetProcAddress( hDbgHelp, "MiniDumpWriteDump" );
1924 
1925         if ( !pMiniDumpWriteDump )
1926         {
1927             FreeLibrary( hDbgHelp );
1928             return false;
1929         }
1930     }
1931 
1932     if ( !pMiniDumpWriteDump )
1933         return false;
1934 
1935     HANDLE  hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId );
1936 
1937     if ( IsValidHandle(hProcess) )
1938     {
1939         TCHAR   szTempPath[MAX_PATH];
1940 
1941 //      if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
1942         if ( GetCrashDataPath( szTempPath ) )
1943         {
1944             TCHAR   szFileName[MAX_PATH];
1945 
1946 //          if ( GetTempFileName( szTempPath, TEXT("DMP"), 0, szFileName ) )
1947             _tcscpy( szFileName, szTempPath );
1948             _tcscat( szFileName, _T("\\crashdat.dmp") );
1949             {
1950                 HANDLE  hFile = CreateFile(
1951                     szFileName,
1952                     GENERIC_READ | GENERIC_WRITE,
1953                     0, NULL,
1954 //                  OPEN_EXISTING,
1955                     CREATE_ALWAYS,
1956                     FILE_ATTRIBUTE_NORMAL, NULL );
1957 
1958                 if ( hFile )
1959                 {
1960                     if ( pExceptionPointers && dwThreadId )
1961                     {
1962                         ExceptionParam.ThreadId = dwThreadId;
1963                         ExceptionParam.ExceptionPointers = pExceptionPointers;
1964                         ExceptionParam.ClientPointers = TRUE;
1965 
1966                         EXCEPTION_POINTERS  aExceptionPointers;
1967                         EXCEPTION_RECORD    aExceptionRecord;
1968 
1969                         ReadProcessMemory(
1970                             hProcess,
1971                             pExceptionPointers,
1972                             &aExceptionPointers,
1973                             sizeof(aExceptionPointers),
1974                             NULL );
1975 
1976 
1977                         ReadProcessMemory(
1978                             hProcess,
1979                             aExceptionPointers.ExceptionRecord,
1980                             &aExceptionRecord,
1981                             sizeof(aExceptionRecord),
1982                             NULL );
1983 
1984                         g_dwExceptionCode = aExceptionRecord.ExceptionCode;
1985 
1986                         lpExceptionParam = &ExceptionParam;
1987                     }
1988 
1989                     fSuccess = pMiniDumpWriteDump( hProcess, dwProcessId, hFile, MiniDumpNormal, lpExceptionParam, NULL, NULL );
1990 
1991                     CloseHandle( hFile );
1992 
1993                     WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL );
1994                     _tcscpy( g_szDumpFileName, szFileName );
1995                 }
1996 
1997                 if ( !fSuccess )
1998                     DeleteFile( szFileName );
1999             }
2000         }
2001 
2002         CloseHandle( hProcess );
2003     }
2004 
2005     FreeLibrary( hDbgHelp );
2006 
2007     return fSuccess;
2008 }
2009 
2010 //***************************************************************************
2011 
FindProcessForImage(LPCTSTR lpImagePath)2012 static DWORD FindProcessForImage( LPCTSTR lpImagePath )
2013 {
2014     DWORD   dwProcessId = 0;
2015     DWORD   aProcesses[1024];
2016     DWORD   dwSize = 0;
2017     TCHAR   szShortImagePath[MAX_PATH];
2018 
2019     if ( GetShortPathName( lpImagePath, szShortImagePath, elementsof(szShortImagePath) ) &&
2020         EnumProcesses( aProcesses, sizeof(aProcesses), &dwSize ) )
2021     {
2022         unsigned nProcesses = dwSize / sizeof(aProcesses[0]);
2023 
2024         for ( unsigned i = 0; !dwProcessId && i < nProcesses; i++ )
2025         {
2026             HANDLE  hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] );
2027 
2028             if ( IsValidHandle(hProcess) )
2029             {
2030                 TCHAR   szModulePath[MAX_PATH+1];
2031 
2032                 if ( GetModuleFileNameEx( hProcess, NULL, szModulePath, MAX_PATH ) )
2033                 {
2034                     TCHAR   szShortModulePath[MAX_PATH];
2035 
2036                     if ( GetShortPathName( szModulePath, szShortModulePath, elementsof(szShortModulePath) ) )
2037                     {
2038                         if ( 0 == _tcsicmp( szShortModulePath, szShortImagePath ) )
2039                             dwProcessId = aProcesses[i];
2040                     }
2041                 }
2042 
2043                 CloseHandle( hProcess );
2044             }
2045         }
2046     }
2047 
2048     return dwProcessId;
2049 }
2050 //***************************************************************************
2051 
ParseCommandArgs(LPDWORD pdwProcessId,PEXCEPTION_POINTERS * ppException,LPDWORD pdwThreadId)2052 static bool ParseCommandArgs( LPDWORD pdwProcessId, PEXCEPTION_POINTERS* ppException, LPDWORD pdwThreadId )
2053 {
2054     int     argc = __argc;
2055 #ifdef __MINGW32__
2056 #ifdef _UNICODE
2057     TCHAR   **argv = reinterpret_cast<TCHAR **>(alloca((argc+1)*sizeof(WCHAR*)));
2058     int *sizes = reinterpret_cast<int *>(alloca(argc*sizeof(int)));
2059     int argsize=0;
2060     char **ptr;
2061     int i;
2062     ptr=__argv;
2063     for (i = 0; i < argc; ++i)
2064     {
2065         sizes[i]=MultiByteToWideChar(CP_ACP, 0, *ptr, -1, NULL, 0);
2066         argsize+=sizes[i]+1;
2067         ++ptr;
2068     }
2069     ++argsize;
2070     TCHAR   *args = reinterpret_cast<TCHAR *>(alloca(argsize*sizeof(WCHAR)));
2071     ptr=__argv;
2072     TCHAR *cptr=args;
2073     for (i = 0; i < argc; ++i)
2074     {
2075         argv[i]=cptr;
2076         MultiByteToWideChar( CP_ACP, 0, *ptr, -1, cptr, sizes[i] );
2077         ++ptr;
2078         cptr+=sizes[i];
2079         *cptr=0;
2080         ++cptr;
2081     }
2082     argv[i]=cptr;
2083     *cptr=0;
2084 #else
2085     TCHAR   **argv = __argv;
2086 #endif
2087 #else
2088     TCHAR   **argv = __targv;
2089 #endif
2090     bool    bSuccess = true;
2091 
2092     for ( int argn = 1; bSuccess && argn < argc; argn++ )
2093     {
2094         if ( 0 == _tcsicmp( argv[argn], _T("-h") ) ||
2095              0 == _tcsicmp( argv[argn], _T("/h") ) ||
2096              0 == _tcsicmp( argv[argn], _T("-?") ) ||
2097              0 == _tcsicmp( argv[argn], _T("/?") ) ||
2098              0 == _tcsicmp( argv[argn], _T("/help") ) ||
2099              0 == _tcsicmp( argv[argn], _T("-help") ) ||
2100              0 == _tcsicmp( argv[argn], _T("--help") )
2101              )
2102         {
2103             HINSTANCE   hInstance = GetModuleHandle(NULL);
2104             TCHAR   szUsage[FORMATBUFSIZE];
2105             TCHAR   szProcess[FORMATBUFSIZE];
2106             TCHAR   szProcessDescription[FORMATBUFSIZE];
2107             TCHAR   szHelpDescription[FORMATBUFSIZE];
2108 
2109             LoadAndFormatString( hInstance, IDS_MSG_CMDLINE_USAGE, szUsage, elementsof(szUsage) );
2110             LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID, szProcess, elementsof(szProcess) );
2111             LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID_DESCRIPTION, szProcessDescription, elementsof(szProcessDescription) );
2112             LoadAndFormatString( hInstance, IDS_MSG_PARAM_HELP_DESCRIPTION, szHelpDescription, elementsof(szHelpDescription) );
2113 
2114             _tprintf(
2115                 TEXT("\n%s: crashrep %s\n\n")
2116                 TEXT("/?, -h[elp]          %s\n\n")
2117                 TEXT("%-20s %s\n\n"),
2118                 szUsage, szProcess, szHelpDescription, szProcess, szProcessDescription
2119                 );
2120 
2121             return true;
2122         }
2123         else if ( 0 == _tcsicmp( argv[argn], _T("-p") ) ||
2124              0 == _tcsicmp( argv[argn], _T("/p") ) )
2125         {
2126             if ( ++argn < argc )
2127                 *pdwProcessId = _tcstoul( argv[argn], NULL, 0 );
2128             else
2129                 bSuccess = false;
2130         }
2131         else if ( 0 == _tcsicmp( argv[argn], _T("-excp") ) ||
2132                   0 == _tcsicmp( argv[argn], _T("/excp") ) )
2133         {
2134             if ( ++argn < argc )
2135                 *ppException = (PEXCEPTION_POINTERS)_tcstoul( argv[argn], NULL, 0 );
2136             else
2137                 bSuccess = false;
2138         }
2139         else if ( 0 == _tcsicmp( argv[argn], _T("-t") ) ||
2140                   0 == _tcsicmp( argv[argn], _T("/t") ) )
2141         {
2142             if ( ++argn < argc )
2143                 *pdwThreadId = _tcstoul( argv[argn], NULL, 0 );
2144             else
2145                 bSuccess = false;
2146         }
2147         else if ( 0 == _tcsicmp( argv[argn], _T("-noui") ) ||
2148                   0 == _tcsicmp( argv[argn], _T("/noui") ) )
2149         {
2150             g_bNoUserInterface = true;
2151         }
2152         else if ( 0 == _tcsicmp( argv[argn], _T("-send") ) ||
2153                   0 == _tcsicmp( argv[argn], _T("/send") ) )
2154         {
2155             g_bSendReport = true;
2156         }
2157         else if ( 0 == _tcsicmp( argv[argn], _T("-load") ) ||
2158                   0 == _tcsicmp( argv[argn], _T("/load") ) )
2159         {
2160             g_bLoadReport = true;
2161         }
2162         else // treat parameter as image path
2163         {
2164             TCHAR   szImagePath[MAX_PATH];
2165             LPTSTR  lpImageName;
2166 
2167             if ( GetFullPathName( argv[argn], MAX_PATH, szImagePath, &lpImageName ) )
2168             {
2169                 DWORD   dwProcessId = FindProcessForImage( szImagePath );
2170 
2171                 if ( dwProcessId )
2172                     *pdwProcessId = dwProcessId;
2173                 else
2174                     bSuccess = false;
2175             }
2176         }
2177     }
2178 
2179     if ( !*pdwProcessId && !g_bLoadReport )
2180     {
2181         TCHAR   szImagePath[MAX_PATH];
2182         LPTSTR  lpImageName;
2183 
2184         if ( GetFullPathName( TEXT("soffice.exe"), MAX_PATH, szImagePath, &lpImageName ) )
2185         {
2186             DWORD   dwProcessId = FindProcessForImage( szImagePath );
2187 
2188             if ( dwProcessId )
2189                 *pdwProcessId = dwProcessId;
2190             else
2191                 bSuccess = false;
2192         }
2193     }
2194 
2195     return bSuccess;
2196 }
2197 
2198 //***************************************************************************
2199 
WriteCommentFile(LPCTSTR lpComment)2200 BOOL WriteCommentFile( LPCTSTR lpComment )
2201 {
2202     BOOL    fSuccess = FALSE;
2203     TCHAR   szTempPath[MAX_PATH];
2204 
2205     if ( GetTempPath( elementsof(szTempPath), szTempPath ) )
2206     {
2207         TCHAR   szFileName[MAX_PATH];
2208 
2209         if ( GetTempFileName( szTempPath, TEXT("CMT"), 0, szFileName ) )
2210         {
2211             HANDLE  hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2212 
2213             if ( hFile )
2214             {
2215                 DWORD   dwBytesWritten;
2216 
2217                 int needed = WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, NULL, 0, NULL, NULL );
2218                 if ( needed )
2219                 {
2220                     char *lpCommentUTF8 = (char *)alloca( needed );
2221                     WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, lpCommentUTF8, needed, NULL, NULL );
2222                     fSuccess = WriteFile( hFile, lpCommentUTF8, strlen(lpCommentUTF8), &dwBytesWritten, NULL );
2223                 }
2224                 else
2225                     fSuccess = TRUE;
2226 
2227 
2228                 CloseHandle( hFile );
2229 
2230                 WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szCommentFileNameA, MAX_PATH, NULL, NULL );
2231             }
2232 
2233             if ( !fSuccess )
2234                 DeleteFile( szFileName );
2235         }
2236     }
2237 
2238     return fSuccess;
2239 }
2240 
2241 //***************************************************************************
2242 
_tsetenv(const _TCHAR * lpVar,const _TCHAR * lpValue)2243 static int _tsetenv( const _TCHAR *lpVar, const _TCHAR *lpValue )
2244 {
2245     if ( !lpValue )
2246         lpValue = _T("");
2247 
2248     _TCHAR  *envstr = (TCHAR *)alloca( (_tcslen( lpVar ) + _tcslen( lpValue ) + 2) * sizeof(_TCHAR) );
2249 
2250     _tcscpy( envstr, lpVar );
2251     _tcscat( envstr, _T("=") );
2252     _tcscat( envstr, lpValue );
2253 
2254     return _tputenv( envstr );
2255 }
2256 
read_line(FILE * fp,string & rLine)2257 static bool read_line( FILE *fp, string& rLine )
2258 {
2259     char szBuffer[1024];
2260     bool bSuccess = false;
2261     bool bEOL = false;
2262     string  line;
2263 
2264 
2265     while ( !bEOL && fgets( szBuffer, sizeof(szBuffer), fp ) )
2266     {
2267         int len = strlen(szBuffer);
2268 
2269         bSuccess = true;
2270 
2271         while ( len && szBuffer[len - 1] == '\n' )
2272         {
2273             szBuffer[--len] = 0;
2274             bEOL = true;
2275         }
2276 
2277         line.append( szBuffer );
2278     }
2279 
2280     rLine = line;
2281     return bSuccess;
2282 }
2283 
get_script_string(const char * pFileName,const char * pKeyName)2284 static string get_script_string( const char *pFileName, const char *pKeyName )
2285 {
2286     FILE    *fp = fopen( pFileName, "rt" );
2287     string  retValue;
2288 
2289     if ( fp )
2290     {
2291         string line;
2292         string section;
2293 
2294         while ( read_line( fp, line ) )
2295         {
2296             line = trim_string( line );
2297 
2298 
2299             string::size_type iEqualSign = line.find( '=', 0 );
2300 
2301             if ( iEqualSign != string::npos )
2302             {
2303                 string  keyname = line.substr( 0, iEqualSign );
2304                 keyname = trim_string( keyname );
2305 
2306                 string  value = line.substr( sal::static_int_cast<string::size_type>(iEqualSign + 1) );
2307                 value = trim_string( value );
2308 
2309                 if ( value.length() && '\"' == value[0] )
2310                 {
2311                     value.erase( 0, 1 );
2312 
2313                     string::size_type iQuotes = value.find( '"', 0 );
2314 
2315                     if ( iQuotes != string::npos )
2316                         value.erase( iQuotes );
2317                 }
2318 
2319                 if ( 0 == stricmp( keyname.c_str(), pKeyName ) )
2320                 {
2321                     retValue = value;
2322                     break;
2323                 }
2324             }
2325         }
2326 
2327         fclose( fp );
2328     }
2329 
2330     return retValue;
2331 }
2332 
ReadBootstrapParams(CrashReportParams & rParams)2333 static bool ReadBootstrapParams( CrashReportParams &rParams )
2334 {
2335     TCHAR   szBuffer[256] = TEXT("");
2336     TCHAR   szModuleName[MAX_PATH];
2337     TCHAR   szModuleVersionName[MAX_PATH];
2338     TCHAR   szDrive[_MAX_DRIVE];
2339     TCHAR   szDir[_MAX_DIR];
2340     TCHAR   szFName[_MAX_FNAME];
2341     TCHAR   szExt[_MAX_EXT];
2342     TCHAR   szReportServer[MAX_HOSTNAME];
2343     TCHAR   szReportPort[256];
2344     bool    bSuccess = false;
2345 
2346     GetModuleFileName( NULL, szModuleName, MAX_PATH );
2347     _tsplitpath( szModuleName, szDrive, szDir, szFName, szExt );
2348     _tmakepath( szModuleName, szDrive, szDir, _T("bootstrap"), _T(".ini") );
2349     _tmakepath( szModuleVersionName, szDrive, szDir, _T("version"), _T(".ini") );
2350 
2351     if (
2352         GetPrivateProfileString(
2353         TEXT("Bootstrap"),
2354         TEXT("ProductKey"),
2355         TEXT("OpenOffice"),
2356         szBuffer,
2357         elementsof(szBuffer),
2358         szModuleName )
2359         )
2360     {
2361         TCHAR   *pVersion = _tcschr( szBuffer, ' ' );
2362 
2363         g_wstrProductKey = szBuffer;
2364 
2365         if ( pVersion )
2366         {
2367             *pVersion = 0;
2368             pVersion++;
2369         }
2370         else
2371             pVersion = TEXT("");
2372 
2373         if ( !_tgetenv( _T("PRODUCTNAME") ) )
2374         {
2375             _tsetenv( TEXT("PRODUCTNAME"), szBuffer );
2376         }
2377         if ( !_tgetenv( _T("PRODUCTVERSION") ) )
2378             _tsetenv( TEXT("PRODUCTVERSION"), pVersion );
2379     }
2380 
2381     GetPrivateProfileString(
2382         TEXT("Version"),
2383         TEXT("buildid"),
2384         TEXT("unknown"),
2385         g_szBuildId, elementsof(g_szBuildId),
2386         szModuleVersionName );
2387 
2388     g_strDefaultLanguage = get_script_string( "instdb.inf", "DefaultLanguage" );
2389 
2390     if ( GetPrivateProfileString(
2391         TEXT("ErrorReport"),
2392         TEXT("ErrorReportPort"),
2393         TEXT("80"),
2394         szReportPort, elementsof(szReportPort),
2395         szModuleName
2396         ) )
2397     {
2398         TCHAR *endptr = NULL;
2399 
2400         unsigned short uReportPort = (unsigned short)_tcstoul( szReportPort, &endptr, 10 );
2401         if ( uReportPort )
2402             g_uReportPort = uReportPort;
2403     }
2404 
2405     if ( GetPrivateProfileString(
2406         TEXT("ErrorReport"),
2407         TEXT("ErrorReportServer"),
2408         TEXT(""),
2409         szReportServer, elementsof(szReportServer),
2410         szModuleName
2411         ) )
2412     {
2413         bSuccess = 0 != WideCharToMultiByte( CP_ACP, 0, szReportServer, -1, g_szReportServerA, elementsof(g_szReportServerA), NULL, NULL );
2414     }
2415 
2416     LPCTSTR lpEnvString;
2417 
2418     if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYSERVER") )) )
2419         rParams.sProxyServer = lpEnvString;
2420 
2421     if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYPORT") )) )
2422         rParams.sProxyPort = lpEnvString;
2423 
2424     if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_SENDERADDRESS") )) )
2425         rParams.sEmail = lpEnvString;
2426 
2427     return bSuccess;
2428 }
2429 
2430 //***************************************************************************
2431 
SendHTTPRequest(FILE * fp,const char * pszServer,unsigned short uPort=80,const char * pszProxyServer=NULL,unsigned short uProxyPort=8080)2432 bool SendHTTPRequest(
2433                 FILE *fp,
2434                 const char *pszServer,
2435                 unsigned short uPort = 80,
2436                 const char *pszProxyServer = NULL,
2437                 unsigned short uProxyPort = 8080 )
2438 {
2439     bool success = false;
2440 
2441     struct hostent *hp;
2442 
2443     if ( pszProxyServer )
2444         hp = gethostbyname( pszProxyServer );
2445     else
2446         hp = gethostbyname( pszServer );
2447 
2448     if ( hp )
2449     {
2450         SOCKET  s = socket( AF_INET, SOCK_STREAM, 0 );
2451 
2452         if ( s )
2453         {
2454             struct sockaddr_in address;
2455 
2456             memcpy(&(address.sin_addr.s_addr), *(hp->h_addr_list),sizeof(struct in_addr));
2457             address.sin_family = AF_INET;
2458 
2459             if ( pszProxyServer )
2460                 address.sin_port = ntohs( uProxyPort );
2461             else
2462                 address.sin_port = ntohs( uPort );
2463 
2464             if ( 0 == connect( s, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) )
2465             {
2466                 fseek( fp, 0, SEEK_END );
2467                 size_t length = ftell( fp );
2468                 fseek( fp, 0, SEEK_SET );
2469 
2470                 char buffer[2048];
2471 
2472                 if ( pszProxyServer )
2473                     sprintf( buffer,
2474                     "POST http://%s:%d/soap/servlet/rpcrouter HTTP/1.0\r\n"
2475                         "Content-Type: text/xml; charset=\"utf-8\"\r\n"
2476                         "Content-Length: %d\r\n"
2477                         "SOAPAction: \"\"\r\n\r\n",
2478                         pszServer,
2479                         uPort,
2480                         length
2481                         );
2482                 else
2483                     sprintf( buffer,
2484                         "POST /soap/servlet/rpcrouter HTTP/1.0\r\n"
2485                         "Content-Type: text/xml; charset=\"utf-8\"\r\n"
2486                         "Content-Length: %d\r\n"
2487                         "SOAPAction: \"\"\r\n\r\n",
2488                         length
2489                         );
2490 
2491                 if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) )
2492                 {
2493                     size_t nBytes;
2494 
2495                     do
2496                     {
2497                         nBytes = fread( buffer, 1, sizeof(buffer), fp );
2498 
2499                         if ( nBytes )
2500                             success = SOCKET_ERROR != send( s, buffer, nBytes, 0 );
2501                     } while( nBytes && success );
2502 
2503                     if ( success )
2504                     {
2505                         memset( buffer, 0, sizeof(buffer) );
2506                         success = SOCKET_ERROR != recv( s, buffer, sizeof(buffer), 0 );
2507                         if ( success )
2508                         {
2509                             char szHTTPSignature[sizeof(buffer)] = "";
2510                             unsigned uHTTPReturnCode = 0;
2511 
2512                             sscanf( buffer, "%s %d ", szHTTPSignature, &uHTTPReturnCode );
2513                             success = uHTTPReturnCode == 200;
2514                         }
2515                     }
2516                 }
2517 
2518             }
2519 
2520             closesocket( s );
2521         }
2522     }
2523 
2524     return success;
2525 }
2526 
2527 //***************************************************************************
2528 
WriteSOAPRequest(FILE * fp)2529 static void WriteSOAPRequest( FILE *fp )
2530 {
2531     fprintf( fp,
2532         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
2533         "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n"
2534         "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n"
2535         "xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\"\n"
2536         "xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\n"
2537         "xmlns:rds=\"urn:ReportDataService\"\n"
2538         "xmlns:apache=\"http://xml.apache.org/xml-soap\"\n"
2539         "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
2540         "<SOAP-ENV:Body>\n"
2541         );
2542 
2543     fprintf( fp, "<rds:submitReport>\n" );
2544     fprintf( fp, "<body xsi:type=\"xsd:string\">This is an autogenerated crash report mail.</body>\n" );
2545     fprintf( fp, "<hash xsi:type=\"apache:Map\">\n" );
2546 
2547     FILE    *fpin = fopen( g_szReportFileNameA, "r" );
2548     if ( fpin )
2549     {
2550         fprintf( fp,
2551             "<item>\n"
2552             "<key xsi:type=\"xsd:string\">reportmail.xml</key>\n"
2553             "<value xsi:type=\"xsd:string\"><![CDATA[" );
2554         fcopy( fpin, fp );
2555         fprintf( fp, "]]></value></item>\n" );
2556         fclose( fpin );
2557     }
2558 
2559     fpin = fopen( g_szCommentFileNameA, "r" );
2560     if ( fpin )
2561     {
2562         fprintf( fp,
2563             "<item>\n"
2564             "<key xsi:type=\"xsd:string\">description.txt</key>\n"
2565             "<value xsi:type=\"xsd:string\"><![CDATA[" );
2566         fcopy( fpin, fp );
2567         fprintf( fp, "]]></value></item>\n" );
2568         fclose( fpin );
2569     };
2570 
2571 
2572     fpin = fopen( g_szDumpFileNameA, "rb" );
2573     if ( fpin )
2574     {
2575         FILE *fptemp = _tmpfile();
2576 
2577         if ( fptemp )
2578         {
2579             if ( base64_encode( fpin, fptemp ) )
2580             {
2581                 fseek( fptemp, 0, SEEK_SET );
2582                 fprintf( fp,
2583                     "<item>\n"
2584                     "<key xsi:type=\"xsd:string\">user.dmp</key>\n"
2585                     "<value xsi:type=\"xsd:string\">" );
2586                 fcopy( fptemp, fp );
2587                 fprintf( fp, "</value></item>\n" );
2588             }
2589             fclose( fptemp );
2590         }
2591         fclose( fpin );
2592     }
2593 
2594     fprintf( fp,
2595         "</hash>\n"
2596         "</rds:submitReport>\n"
2597         "</SOAP-ENV:Body>\n"
2598         "</SOAP-ENV:Envelope>\n"
2599         );
2600 }
2601 
2602 //***************************************************************************
2603 
2604 struct RequestParams
2605 {
2606     bool    success;
2607     FILE    *fpin;
2608     const char *lpServer;
2609     unsigned short uPort;
2610     const char *lpProxyServer;
2611     unsigned short uProxyPort;
2612     HWND    hwndStatus;
2613 };
2614 
SendingThread(void * lpArgs)2615 void _cdecl SendingThread( void *lpArgs )
2616 {
2617     RequestParams *pParams = (RequestParams *)lpArgs;
2618 
2619     pParams->success = SendHTTPRequest( pParams->fpin, pParams->lpServer, pParams->uPort, pParams->lpProxyServer, pParams->uProxyPort );
2620 
2621     PostMessage( pParams->hwndStatus, WM_COMMAND, IDOK, 0 );
2622 }
2623 
2624 //***************************************************************************
2625 
SendingStatusDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)2626 INT_PTR CALLBACK SendingStatusDialogProc(
2627     HWND hwndDlg,
2628     UINT uMsg,
2629     WPARAM wParam,
2630     LPARAM lParam
2631     )
2632 {
2633     static RequestParams *pRequest = NULL;
2634     static HANDLE hSendingThread = NULL;
2635 
2636     switch ( uMsg )
2637     {
2638     case WM_INITDIALOG:
2639         {
2640             TCHAR   szBuffer[1024] = TEXT("");
2641             HINSTANCE   hInstance = (HINSTANCE)GetWindowLongPtr( hwndDlg, GWLP_HINSTANCE );
2642             //HWND  hwndParent = (HWND)GetWindowLongPtr( hwndDlg, GWLP_HWNDPARENT );
2643 
2644             pRequest = (RequestParams *)lParam;
2645 
2646             LoadAndFormatString( hInstance, IDS_SENDING_REPORT_HEADER, szBuffer, elementsof(szBuffer) );
2647             SetWindowText( hwndDlg, szBuffer );
2648 
2649             LoadAndFormatString( hInstance, IDS_SENDING_REPORT_STATUS, szBuffer, elementsof(szBuffer) );
2650             Static_SetText( GetDlgItem(hwndDlg, IDC_SENDING_REPORT_STATUS), szBuffer );
2651 
2652             LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) );
2653             Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer );
2654 
2655             pRequest->hwndStatus = hwndDlg;
2656 
2657             hSendingThread = (HANDLE)_beginthread( SendingThread, 0, pRequest );
2658         }
2659         return TRUE;
2660     case WM_COMMAND:
2661         switch ( LOWORD(wParam) )
2662         {
2663         case IDCANCEL:
2664             TerminateThread( hSendingThread, 0 );
2665         case IDOK:
2666             WaitForSingleObject( hSendingThread, INFINITE );
2667             CloseHandle( hSendingThread );
2668             EndDialog( hwndDlg, wParam );
2669             return TRUE;
2670         }
2671         break;
2672     default:
2673         break;
2674     }
2675 
2676     return FALSE;
2677 }
2678 
2679 //***************************************************************************
2680 
SendCrashReport(HWND hwndParent,const CrashReportParams & rParams)2681 bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams )
2682 {
2683     bool success = false;
2684     char szProxyServer[1024] = "";
2685     unsigned short uProxyPort = 8080;
2686     TCHAR *endptr = NULL;
2687 
2688     switch ( rParams.uInternetConnection )
2689     {
2690     case 2:
2691         {
2692             WideCharToMultiByte(
2693                 CP_ACP, 0, rParams.sProxyServer.c_str(), -1,
2694                 szProxyServer, sizeof(szProxyServer), NULL, NULL );
2695             uProxyPort = (unsigned short)_tcstoul( rParams.sProxyPort.c_str(), &endptr, 10 );
2696         }
2697         break;
2698     case 0:
2699         {
2700             DWORD   dwProxyEnable = 0;
2701 
2702             RegReadValue( HKEY_CURRENT_USER,
2703                 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
2704                 TEXT("ProxyEnable"),
2705                 &dwProxyEnable,
2706                 sizeof(dwProxyEnable) );
2707 
2708             if ( dwProxyEnable )
2709             {
2710                 TCHAR   tszProxyServers[1024] = TEXT("");
2711 
2712                 if ( ERROR_SUCCESS == RegReadValue( HKEY_CURRENT_USER,
2713                     TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
2714                     TEXT("ProxyServer"),
2715                     tszProxyServers,
2716                     sizeof(tszProxyServers) ) )
2717                 {
2718                     TCHAR *lpHttpStart = _tcsstr( tszProxyServers, TEXT("http=") );
2719 
2720                     if ( lpHttpStart )
2721                         lpHttpStart += 5;
2722                     else
2723                         lpHttpStart = tszProxyServers;
2724 
2725                     TCHAR *lpHttpEnd = _tcschr( lpHttpStart, ';' );
2726 
2727                     if ( lpHttpEnd )
2728                         *lpHttpEnd = 0;
2729 
2730                     char    szHTTPProxyServer[1024] = "";
2731                     WideCharToMultiByte( CP_ACP, 0, lpHttpStart, -1, szHTTPProxyServer, sizeof(szHTTPProxyServer), NULL, NULL );
2732 
2733                     char *lpColon = strchr( szHTTPProxyServer, ':' );
2734 
2735                     if ( lpColon )
2736                     {
2737                         char *endptr = NULL;
2738 
2739                         *lpColon = 0;
2740                         uProxyPort = (unsigned short)strtoul( lpColon + 1, &endptr, 10 );
2741                     }
2742                     else
2743                         uProxyPort = 8080;
2744 
2745                     strcpy( szProxyServer, szHTTPProxyServer );
2746 
2747                 }
2748             }
2749         }
2750         break;
2751     default:
2752     case 1:
2753         break;
2754     }
2755 
2756     FILE    *fptemp = _tmpfile();
2757     if ( fptemp )
2758     {
2759         RequestParams   request;
2760 
2761         request.success = false;
2762         request.fpin = fptemp;
2763         request.lpServer = REPORT_SERVER;
2764         request.uPort = REPORT_PORT;
2765         request.lpProxyServer = szProxyServer[0] ? szProxyServer : NULL;
2766         request.uProxyPort = uProxyPort;
2767         request.hwndStatus = NULL;
2768 
2769         WriteSOAPRequest( fptemp );
2770         fseek( fptemp, 0, SEEK_SET );
2771 
2772         if ( hwndParent )
2773         {
2774             int retid = DialogBoxParam(
2775                 GetModuleHandle(NULL),
2776                 MAKEINTRESOURCE(IDD_SENDING_STATUS),
2777                 hwndParent,
2778                 SendingStatusDialogProc,
2779                 (LPARAM)&request
2780                 );
2781 
2782             success = request.success;
2783 
2784             if ( IDOK == retid )
2785             {
2786                 if ( !success )
2787                 {
2788                     TCHAR   szMessage[1024];
2789 
2790                     LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
2791 
2792                     MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
2793                 }
2794                 else
2795                 {
2796                     TCHAR   szMessage[1024];
2797                     TCHAR   szTitle[1024];
2798 
2799                     LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
2800                     LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_HEADER, szTitle, elementsof(szTitle) );
2801 
2802                     MessageBox( hwndParent, szMessage, szTitle, MB_ICONINFORMATION | MB_OK );
2803                 }
2804             }
2805 
2806         }
2807         else
2808         {
2809             HANDLE hSendingThread = (HANDLE)_beginthread( SendingThread, 0, (void *)&request );
2810 
2811             WaitForSingleObject( hSendingThread, INFINITE );
2812 
2813             success = request.success;
2814             if ( !success )
2815             {
2816                 TCHAR   szMessage[1024];
2817 
2818                 LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) );
2819                 _ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
2820             }
2821             else
2822             {
2823                 TCHAR   szMessage[1024];
2824 
2825                 LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) );
2826 
2827                 _ftprintf( stderr, _T("SUCCESS: %s\n"), szMessage );
2828             }
2829         }
2830         fclose( fptemp );
2831     }
2832     else
2833     {
2834         TCHAR   szMessage[1024];
2835 
2836         LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_DISK_FULL, szMessage, elementsof(szMessage) );
2837 
2838         if ( hwndParent )
2839             MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK );
2840         else
2841             _ftprintf( stderr, _T("ERROR: %s\n"), szMessage );
2842     }
2843 
2844     return success;
2845 }
2846 
2847 //***************************************************************************
2848 
2849 #ifdef __MINGW32__
WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR,int)2850 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR /*lpCmdLine*/, int )
2851 #else
2852 int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR /*lpCmdLine*/, int )
2853 #endif
2854 {
2855     int exitcode = -1;
2856     int argc = __argc;
2857 
2858 #ifdef __MINGW32__
2859     char **argv = __argv;
2860 #else
2861 #ifdef _UNICODE
2862     char **argv = new char *[argc + 1];
2863 
2864     for ( int argn = 0; argn < argc; argn++ )
2865     {
2866         int nBytes = WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, NULL, 0, NULL, NULL );
2867         argv[argn] = new char[nBytes];
2868         WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, argv[argn], nBytes, NULL, NULL );
2869     }
2870     argv[argc] = NULL;
2871 #else
2872     char **argv = __targv;
2873 #endif
2874 #endif
2875 
2876     osl_setCommandArgs( argc, argv );
2877 
2878     PEXCEPTION_POINTERS pExceptionPointers = NULL;
2879     DWORD               dwProcessId = 0;
2880     DWORD               dwThreadId = 0;
2881 
2882     WSADATA wsaData;
2883     WORD    wVersionRequested;
2884 
2885     wVersionRequested = MAKEWORD(1, 1);
2886     WSAStartup(wVersionRequested, &wsaData);
2887 
2888     CrashReportParams   Params;
2889 
2890     Params.ReadFromRegistry();
2891     Params.ReadFromEnvironment();
2892 
2893     if ( ReadBootstrapParams( Params ) &&
2894         ParseCommandArgs( &dwProcessId, &pExceptionPointers, &dwThreadId ) )
2895     {
2896         bool    bGotDumpFile;
2897 
2898         if ( g_bLoadReport )
2899             bGotDumpFile = FindDumpFile();
2900         else
2901             bGotDumpFile = WriteDumpFile( dwProcessId, pExceptionPointers, dwThreadId );
2902 
2903         if( bGotDumpFile )
2904         {
2905             hash_map< string, string > aLibraries;
2906 
2907             if ( g_bLoadReport )
2908             {
2909                 g_fpStackFile = _open_reportfile( _T(".stk"), _T("rb") );
2910                 g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("rb") );
2911             }
2912             else
2913             {
2914                 if ( g_bSendReport )
2915                 {
2916                     g_fpStackFile = _tmpfile();
2917                     g_fpChecksumFile = _tmpfile();
2918                 }
2919                 else
2920                 {
2921                     g_fpStackFile = _open_reportfile( _T(".stk"), _T("w+b") );
2922                     g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("w+b") );
2923 
2924                     FILE    *fpUnsent = _open_reportfile( _T(".lck"), _T("w+b") );
2925                     if ( fpUnsent )
2926                     {
2927                         fprintf( fpUnsent, "Unsent\r\n" );
2928                         fclose( fpUnsent );
2929                     }
2930                 }
2931 
2932                 WriteStackFile( g_fpStackFile, aLibraries, dwProcessId, pExceptionPointers );
2933                 WriteChecksumFile( g_fpChecksumFile, aLibraries );
2934                 WriteReportFile( &Params );
2935 
2936                 FILE    *fpPreview = _open_reportfile( _T(".prv"), _T("w+b") );
2937 
2938                 if ( fpPreview )
2939                 {
2940                     FILE     *fp = fopen( g_szReportFileNameA, "rb" );
2941                     if ( fp )
2942                     {
2943                         fcopy( fp, fpPreview );
2944                         fclose( fp );
2945                     }
2946                     fclose( fpPreview );
2947                 }
2948             }
2949 
2950             if ( g_bSendReport )
2951             {
2952                 InitCommonControls();
2953 
2954                 // Actually this should never be true anymore
2955                 if ( !g_bNoUserInterface && InitRichEdit() )
2956                 {
2957 
2958                     INT_PTR result = DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG_FRAME), NULL, DialogProc, (LPARAM)&Params );
2959 
2960                     if ( result > 0 )
2961                     {
2962                         exitcode = 0;
2963                     }
2964                     DeinitRichEdit();
2965                 }
2966                 else
2967                 {
2968                     WriteCommentFile( Params.sComment.c_str() );
2969                     WriteReportFile( &Params );
2970                     if ( SendCrashReport( NULL, Params ) )
2971                         exitcode = 0;
2972                 }
2973 
2974 
2975                 if ( g_szReportFileNameA[0] )
2976                     DeleteFileA( g_szReportFileNameA );
2977 
2978                 if ( g_szCommentFileNameA[0] )
2979                     DeleteFileA( g_szCommentFileNameA );
2980             }
2981             else
2982             {
2983                 if ( g_szReportFileNameA[0] )
2984                     DeleteFileA( g_szReportFileNameA );
2985                 exitcode = 0;
2986             }
2987 
2988             if ( g_szDumpFileNameA[0] && g_bSendReport )
2989                     DeleteFileA( g_szDumpFileNameA );
2990 
2991             if ( g_fpStackFile )
2992                 fclose( g_fpStackFile );
2993 
2994             if ( g_fpChecksumFile )
2995                 fclose( g_fpChecksumFile );
2996         }
2997     }
2998 
2999 
3000     return exitcode;
3001 }
3002