| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #define UNICODE |
| #define WIN32_LEAN_AND_MEAN |
| #if defined _MSC_VER |
| #pragma warning(push, 1) |
| #pragma warning(disable:4917) |
| #endif |
| #include <windows.h> |
| #include <windowsx.h> |
| |
| #include <mapi.h> |
| #include <commctrl.h> |
| #include <commdlg.h> |
| #include <psapi.h> |
| |
| #include <shellapi.h> |
| #include <shlobj.h> |
| |
| #define _UNICODE |
| #include <tchar.h> |
| |
| #define _RICHEDIT_VER 0x0200 |
| #include <richedit.h> |
| |
| #if defined _MSC_VER |
| #pragma warning(pop) |
| #endif |
| |
| #if _RICHEDIT_VER >= 0x0200 |
| #define RICHEDIT TEXT("riched20.dll") |
| #else |
| #define RICHEDIT TEXT("riched32.dll") |
| #endif |
| |
| #include <systools/win32/uwinapi.h> |
| #include <rtl/digest.h> |
| #include <rtl/bootstrap.hxx> |
| #include <osl/file.hxx> |
| #include <osl/process.h> |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <io.h> |
| #include <fcntl.h> |
| #include <string> |
| #include <hash_map> |
| #include <winsock.h> |
| #include <malloc.h> |
| #include <process.h> |
| |
| #include <_version.h> |
| |
| #include "resource.h" |
| #include "base64.h" |
| |
| #define FORMATBUFSIZE (8*1024) |
| #define MAX_TEXT_BUFFER (32*1024-1) |
| #define MAX_HOSTNAME (1024) |
| |
| #ifdef __MINGW32__ |
| #include <imagehlp.h> |
| #else |
| #include <dbghelp.h> |
| #endif |
| |
| #ifdef _UNICODE |
| #define tstring wstring |
| #else |
| #define tstring string |
| #endif |
| |
| using namespace ::std; |
| |
| |
| wstring g_wstrProductKey; |
| string g_strDefaultLanguage; |
| FILE *g_fpStackFile = NULL; |
| FILE *g_fpChecksumFile = NULL; |
| DWORD g_dwExceptionCode = 0; |
| |
| CHAR g_szReportServerA[MAX_HOSTNAME] = ""; |
| USHORT g_uReportPort = 80; |
| |
| TCHAR g_szBuildId[256] = TEXT(""); |
| |
| TCHAR g_szDumpFileName[MAX_PATH] = TEXT(""); |
| |
| CHAR g_szDumpFileNameA[MAX_PATH] = ""; |
| CHAR g_szCommentFileNameA[MAX_PATH] = ""; |
| CHAR g_szReportFileNameA[MAX_PATH] = ""; |
| |
| |
| bool g_bNoUserInterface = false; |
| bool g_bSendReport = false; |
| bool g_bLoadReport = false; |
| |
| #define REPORT_SERVER g_szReportServerA |
| #define REPORT_PORT g_uReportPort |
| |
| |
| //*************************************************************************** |
| // tmpfile from msvcrt creates the temporary file in the root of the current |
| // volume and can fail. |
| |
| static FILE *_xfopen( const _TCHAR *file, const _TCHAR *mode ) |
| { |
| #ifdef UNICODE |
| if ( (LONG)GetVersion() < 0 ) |
| { |
| char afile[MAX_PATH]; |
| char amode[16]; |
| |
| WideCharToMultiByte( CP_ACP, 0, file, -1, afile, MAX_PATH, NULL, NULL ); |
| WideCharToMultiByte( CP_ACP, 0, mode, -1, amode, 16, NULL, NULL ); |
| |
| |
| return fopen( afile, amode ); |
| } |
| else |
| #endif |
| return _tfopen( file, mode ); |
| } |
| |
| |
| static FILE *_tmpfile(void) |
| { |
| FILE *fp = NULL; |
| |
| TCHAR szTempPath[MAX_PATH]; |
| |
| if ( GetTempPath( elementsof(szTempPath), szTempPath ) ) |
| { |
| TCHAR szFileName[MAX_PATH]; |
| |
| if ( GetTempFileName( szTempPath, TEXT("CRT"), 0, szFileName ) ) |
| { |
| HANDLE hFile = CreateFile( |
| szFileName, |
| GENERIC_READ | GENERIC_WRITE, |
| 0, NULL, |
| OPEN_EXISTING, |
| FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_NORMAL, |
| NULL ); |
| |
| if ( IsValidHandle( hFile ) ) |
| { |
| int fd = _open_osfhandle( (int)hFile, 0 ); |
| |
| fp = _fdopen( fd, "w+b" ); |
| } |
| } |
| } |
| |
| return fp; |
| } |
| //*************************************************************************** |
| |
| static BOOL GetCrashDataPath( LPTSTR szBuffer ) |
| { |
| ::rtl::OUString ustrValue = ::rtl::OUString::createFromAscii("${$OOO_BASE_DIR/program/bootstrap.ini:UserInstallation}"); |
| ::rtl::Bootstrap::expandMacros( ustrValue ); |
| |
| if ( ustrValue.getLength() ) |
| { |
| ustrValue += ::rtl::OUString::createFromAscii("/user/crashdata"); |
| |
| ::osl::FileBase::RC result = ::osl::Directory::createPath( ustrValue ); |
| |
| if ( ::osl::FileBase::E_None == result || ::osl::FileBase::E_EXIST == result ) |
| { |
| ::rtl::OUString ustrPath; |
| |
| result = ::osl::FileBase::getSystemPathFromFileURL( ustrValue, ustrPath ); |
| if ( ::osl::FileBase::E_None == result ) |
| { |
| _tcsncpy( szBuffer, reinterpret_cast<LPCWSTR>(ustrPath.getStr()), MAX_PATH ); |
| return TRUE; |
| } |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| |
| static FILE *_open_reportfile( LPCTSTR lpExt, LPCTSTR lpMode ) |
| { |
| FILE *fp = NULL; |
| TCHAR szAppDataPath[MAX_PATH] = _T(""); |
| |
| if ( GetCrashDataPath( szAppDataPath ) ) |
| { |
| _tcscat( szAppDataPath, _T("\\crashdat") ); |
| _tcscat( szAppDataPath, lpExt ); |
| |
| fp = _xfopen( szAppDataPath, lpMode ); |
| } |
| |
| return fp; |
| } |
| |
| //*************************************************************************** |
| |
| struct CrashReportParams |
| { |
| BOOL fAllowContact; |
| tstring sEmail; |
| tstring sTitle; |
| tstring sComment; |
| ULONG uInternetConnection; |
| tstring sProxyServer; |
| tstring sProxyPort; |
| |
| CrashReportParams(); |
| |
| void WriteToRegistry(); |
| void ReadFromRegistry(); |
| void ReadFromEnvironment(); |
| }; |
| |
| bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams ); |
| BOOL WriteCommentFile( LPCTSTR lpComment ); |
| |
| //*************************************************************************** |
| |
| LONG RegReadValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPVOID lpData, DWORD cbData ) |
| { |
| HKEY hKey = NULL; |
| LONG lResult; |
| |
| lResult = RegOpenKeyEx( hBaseKey, lpSubKey, 0, KEY_QUERY_VALUE, &hKey ); |
| |
| if ( ERROR_SUCCESS == lResult ) |
| { |
| lResult = RegQueryValueEx( hKey, lpValueName, NULL, NULL, (LPBYTE)lpData, &cbData ); |
| RegCloseKey( hKey ); |
| } |
| |
| return lResult; |
| } |
| |
| //*************************************************************************** |
| |
| LONG RegWriteValue( HKEY hBaseKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, DWORD dwType, LPCVOID lpData, DWORD cbData ) |
| { |
| HKEY hKey = NULL; |
| LONG lResult; |
| |
| lResult = RegCreateKeyEx( hBaseKey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); |
| |
| if ( ERROR_SUCCESS == lResult ) |
| { |
| lResult = RegSetValueEx( hKey, lpValueName, NULL, dwType, (CONST BYTE *)lpData, cbData ); |
| RegCloseKey( hKey ); |
| } |
| |
| return lResult; |
| } |
| |
| //*************************************************************************** |
| |
| CrashReportParams::CrashReportParams() |
| { |
| fAllowContact = FALSE; |
| sTitle = TEXT(""); |
| sComment = TEXT(""); |
| sEmail = TEXT(""); |
| uInternetConnection = 0; |
| sProxyServer = TEXT(""); |
| sProxyPort = TEXT(""); |
| } |
| |
| //*************************************************************************** |
| |
| void CrashReportParams::ReadFromRegistry() |
| { |
| TCHAR szBuffer[2048]; |
| |
| if ( ERROR_SUCCESS == RegReadValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("HTTPProxyServer"), |
| szBuffer, |
| sizeof(szBuffer) ) ) |
| sProxyServer = szBuffer; |
| |
| DWORD dwProxyPort; |
| |
| if ( ERROR_SUCCESS == RegReadValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("HTTPProxyPort"), |
| &dwProxyPort, |
| sizeof(dwProxyPort) ) ) |
| { |
| _stprintf( szBuffer, TEXT("%d"), dwProxyPort ); |
| sProxyPort = szBuffer; |
| } |
| |
| if ( ERROR_SUCCESS == RegReadValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("ReturnAddress"), |
| szBuffer, |
| sizeof(szBuffer) ) ) |
| sEmail = szBuffer; |
| |
| RegReadValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("AllowContact"), |
| &fAllowContact, |
| sizeof(fAllowContact) ); |
| |
| RegReadValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("HTTPConnection"), |
| &uInternetConnection, |
| sizeof(uInternetConnection) ); |
| } |
| |
| //*************************************************************************** |
| |
| void CrashReportParams::WriteToRegistry() |
| { |
| RegWriteValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("HTTPProxyServer"), REG_SZ, |
| sProxyServer.c_str(), |
| sizeof(TCHAR) * (sProxyServer.length() + 1) ); |
| |
| LPTSTR endptr = NULL; |
| DWORD dwProxyPort = _tcstoul( sProxyPort.c_str(), &endptr, 10 ); |
| |
| RegWriteValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("HTTPProxyPort"), REG_DWORD, |
| &dwProxyPort, |
| sizeof(DWORD) ); |
| |
| RegWriteValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("AllowContact"), REG_DWORD, |
| &fAllowContact, |
| sizeof(DWORD) ); |
| |
| |
| RegWriteValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("HTTPConnection"), REG_DWORD, |
| &uInternetConnection, |
| sizeof(DWORD) ); |
| |
| RegWriteValue( |
| HKEY_CURRENT_USER, |
| TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), |
| TEXT("ReturnAddress"), REG_SZ, |
| sEmail.c_str(), |
| sizeof(TCHAR) * (sEmail.length() + 1) ); |
| } |
| |
| //*************************************************************************** |
| |
| void CrashReportParams::ReadFromEnvironment() |
| { |
| TCHAR szBuffer[2048]; |
| |
| DWORD dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPPROXYSERVER"), szBuffer, elementsof(szBuffer) ); |
| |
| if ( dwResult && dwResult < elementsof(szBuffer) ) |
| sProxyServer = szBuffer; |
| |
| dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPPROXYPORT"), szBuffer, elementsof(szBuffer) ); |
| |
| if ( dwResult && dwResult < elementsof(szBuffer) ) |
| sProxyPort = szBuffer; |
| |
| dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_RETURNADDRESS"), szBuffer, elementsof(szBuffer) ); |
| |
| if ( dwResult && dwResult < elementsof(szBuffer) ) |
| { |
| sEmail = szBuffer; |
| // fAllowContact = TRUE; |
| } |
| |
| dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_HTTPCONNECTIONTYPE"), szBuffer, elementsof(szBuffer) ); |
| |
| if ( dwResult && dwResult < elementsof(szBuffer) ) |
| { |
| if ( 0 == _tcsicmp( szBuffer, _T("DIRECT") ) ) |
| uInternetConnection = 1; |
| else if ( 0 == _tcsicmp( szBuffer, _T("MANUALPROXY") ) ) |
| uInternetConnection = 2; |
| else if ( 0 == _tcsicmp( szBuffer, _T("SYSTEMDEFAULT") ) ) |
| uInternetConnection = 0; |
| } |
| |
| dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_SUBJECT"), szBuffer, elementsof(szBuffer) ); |
| |
| if ( dwResult && dwResult < elementsof(szBuffer) ) |
| sTitle = szBuffer; |
| |
| |
| dwResult = GetEnvironmentVariable( TEXT("ERRORREPORT_BODYFILE"), szBuffer, elementsof(szBuffer) ); |
| |
| if ( dwResult && dwResult < elementsof(szBuffer) ) |
| { |
| FILE *fp = _xfopen( szBuffer, _T("rb") ); |
| |
| if ( fp ) |
| { |
| CHAR aUTF8Buffer[256]; |
| size_t nBytesRead; |
| |
| sComment = TEXT(""); |
| |
| while ( 0 != (nBytesRead = fread( aUTF8Buffer, sizeof(aUTF8Buffer[0]), elementsof(aUTF8Buffer), fp )) ) |
| { |
| TCHAR aBuffer[256+1]; |
| |
| DWORD dwCharacters = MultiByteToWideChar( CP_UTF8, 0, aUTF8Buffer, nBytesRead, aBuffer, elementsof(aBuffer) - 1 ); |
| aBuffer[dwCharacters] = 0; |
| sComment += aBuffer; |
| } |
| |
| fclose( fp ); |
| } |
| } |
| } |
| |
| //*************************************************************************** |
| |
| typedef BOOL (WINAPI *MiniDumpWriteDump_PROC)( |
| IN HANDLE hProcess, |
| IN DWORD ProcessId, |
| IN HANDLE hFile, |
| IN MINIDUMP_TYPE DumpType, |
| IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL |
| IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL |
| IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL |
| ); |
| |
| //*************************************************************************** |
| |
| static BOOL WINAPI InitRichEdit() |
| { |
| return (NULL != LoadLibrary( RICHEDIT )); |
| } |
| |
| //*************************************************************************** |
| |
| static BOOL WINAPI DeinitRichEdit() |
| { |
| return FreeLibrary( GetModuleHandle( RICHEDIT ) ); |
| } |
| |
| //*************************************************************************** |
| |
| static string trim_string( const string& rString ) |
| { |
| string temp = rString; |
| |
| while ( temp.length() && temp[0] == ' ' || temp[0] == '\t' ) |
| temp.erase( 0, 1 ); |
| |
| string::size_type len = temp.length(); |
| |
| while ( len && temp[len-1] == ' ' || temp[len-1] == '\t' ) |
| { |
| temp.erase( len - 1, 1 ); |
| len = temp.length(); |
| } |
| |
| return temp; |
| } |
| |
| //*************************************************************************** |
| |
| static int LoadAndFormatString( HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax ) |
| { |
| TCHAR szBuffer[FORMATBUFSIZE]; |
| TCHAR szBuffer2[FORMATBUFSIZE]; |
| |
| LoadString( hInstance, uID, szBuffer, elementsof(szBuffer) ); |
| |
| LPCTSTR src; |
| LPTSTR dest; |
| for ( dest = szBuffer2, src = szBuffer; *src; src++, dest++ ) |
| { |
| switch ( *src ) |
| { |
| case '~': |
| *dest = '&'; |
| break; |
| case '\\': |
| switch ( *(++src) ) |
| { |
| case 'n': |
| *dest = '\n'; |
| break; |
| case 'r': |
| *dest = '\r'; |
| break; |
| default: |
| *dest = *src; |
| break; |
| } |
| break; |
| default: |
| *dest = *src; |
| break; |
| } |
| } |
| |
| *dest = *src; |
| |
| return ExpandEnvironmentStrings( szBuffer2, lpBuffer, nBufferMax ); |
| } |
| |
| |
| //*************************************************************************** |
| |
| static string wstring2utf8( const wstring &rString ) |
| { |
| int nBufSize = WideCharToMultiByte( CP_UTF8, 0, rString.c_str(), -1, NULL, 0, NULL, FALSE ); |
| |
| LPSTR pBuffer = (LPSTR)alloca( nBufSize ); |
| |
| WideCharToMultiByte( CP_UTF8, 0, rString.c_str(), -1, pBuffer, nBufSize, NULL, FALSE ); |
| |
| return string( pBuffer ); |
| } |
| |
| //*************************************************************************** |
| |
| static string xml_encode( const string &rString ) |
| { |
| string temp = rString; |
| string::size_type pos = 0; |
| |
| // First replace all occurences of '&' because it may occur in further |
| // encoded chardters too |
| |
| for( pos = 0; (pos = temp.find( '&', pos )) != string::npos; pos += 4 ) |
| temp.replace( pos, 1, "&" ); |
| |
| for( pos = 0; (pos = temp.find( '<', pos )) != string::npos; pos += 4 ) |
| temp.replace( pos, 1, "<" ); |
| |
| for( pos = 0; (pos = temp.find( '>', pos )) != string::npos; pos += 4 ) |
| temp.replace( pos, 1, ">" ); |
| |
| return temp; |
| } |
| |
| //*************************************************************************** |
| |
| static size_t fcopy( FILE *fpin, FILE *fpout ) |
| { |
| char buffer[1024]; |
| size_t nBytes; |
| size_t nBytesWritten = 0; |
| |
| if ( fpin && fpout ) |
| { |
| while ( 0 != (nBytes = fread( buffer, 1, sizeof(buffer), fpin )) ) |
| { |
| nBytesWritten += fwrite( buffer, 1, nBytes, fpout ); |
| } |
| } |
| |
| return nBytesWritten; |
| } |
| |
| //*************************************************************************** |
| |
| static string GetModuleDirectory( HMODULE hModule ) |
| { |
| TCHAR szModuleName[MAX_PATH] = TEXT(""); |
| TCHAR szDrive[_MAX_DRIVE]; |
| TCHAR szDir[_MAX_DIR]; |
| TCHAR szFName[_MAX_FNAME]; |
| TCHAR szExt[_MAX_EXT]; |
| |
| if ( GetModuleFileName( hModule, szModuleName, MAX_PATH ) ) |
| { |
| _tsplitpath( szModuleName, szDrive, szDir, szFName, szExt ); |
| _tmakepath( szModuleName, szDrive, szDir, _T(""), _T("") ); |
| } |
| |
| CHAR szModuleNameUTF8[MAX_PATH] = ""; |
| |
| WideCharToMultiByte( CP_UTF8, 0, szModuleName, -1, szModuleNameUTF8, elementsof(szModuleNameUTF8), NULL, NULL ); |
| return string( szModuleNameUTF8 ); |
| } |
| |
| //*************************************************************************** |
| |
| string GetFileDirectory( const string& rFilePath ) |
| { |
| string aDir = rFilePath; |
| size_t pos = aDir.rfind( '\\' ); |
| |
| if ( string::npos != pos ) |
| aDir.erase( pos + 1 ); |
| else |
| aDir = ""; |
| |
| return aDir; |
| } |
| |
| //*************************************************************************** |
| |
| string GetFileName( const string& rFilePath ) |
| { |
| string aName = rFilePath; |
| size_t pos = aName.rfind( '\\' ); |
| |
| if ( string::npos != pos ) |
| return aName.substr( pos + 1 ); |
| else |
| return aName; |
| } |
| |
| //*************************************************************************** |
| |
| BOOL WriteReportFile( CrashReportParams *pParams ) |
| { |
| BOOL fSuccess = FALSE; |
| TCHAR szTempPath[MAX_PATH]; |
| |
| if ( GetTempPath( elementsof(szTempPath), szTempPath ) ) |
| { |
| TCHAR szFileName[MAX_PATH]; |
| |
| if ( GetTempFileName( szTempPath, TEXT("RPM"), 0, szFileName ) ) |
| { |
| HANDLE hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); |
| |
| if ( hFile ) |
| { |
| int fd = _open_osfhandle( (LONG)hFile, _O_TEXT ); |
| FILE *fp = _fdopen( fd, "w+t" ); |
| CHAR szTitle[1024] = ""; |
| CHAR szBuildId[1024] = ""; |
| CHAR szEmail[1024] = ""; |
| const char *pszUserType = getenv( "STAROFFICE_USERTYPE" ); |
| |
| WideCharToMultiByte( CP_UTF8, 0, pParams->sTitle.c_str(), -1, szTitle, sizeof(szTitle), NULL, NULL ); |
| WideCharToMultiByte( CP_UTF8, 0, g_szBuildId, -1, szBuildId, sizeof(szBuildId), NULL, NULL ); |
| WideCharToMultiByte( CP_UTF8, 0, pParams->sEmail.c_str(), -1, szEmail, sizeof(szEmail), NULL, NULL ); |
| |
| fprintf( fp, |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| "<!DOCTYPE errormail:errormail PUBLIC \"-//OpenOffice.org//DTD ErrorMail 1.0//EN\" \"errormail.dtd\">\n" |
| "<errormail:errormail xmlns:errormail=\"http://openoffice.org/2002/errormail\" usertype=\"%s\">\n" |
| "<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.1\" feedback=\"%s\" email=\"%s\">\n", |
| pszUserType ? pszUserType : "", |
| pParams->fAllowContact ? "true" : "false", |
| pParams->fAllowContact ? xml_encode(szEmail).c_str() : "" |
| ); |
| |
| fprintf( fp, |
| "<reportmail:title>%s</reportmail:title>\n", |
| xml_encode(szTitle).c_str() ); |
| |
| fprintf( fp, |
| "<reportmail:attachment name=\"description.txt\" media-type=\"text/plain;charset=UTF-8\" class=\"UserComment\"/>\n" |
| "<reportmail:attachment name=\"user.dmp\" media-type=\"application/octet-stream\" class=\"UserDump\"/>\n" |
| "</reportmail:mail>\n" |
| |
| "<officeinfo:officeinfo xmlns:officeinfo=\"http://openoffice.org/2002/officeinfo\" build=\"%s\" platform=\"%s\" language=\"%s\" procpath=\"%s\" exceptiontype=\"0x%08X\" product=\"%s\"/>\n", |
| szBuildId, |
| _INPATH, |
| xml_encode(g_strDefaultLanguage).c_str(), |
| xml_encode(GetModuleDirectory( NULL )).c_str(), |
| g_dwExceptionCode, |
| xml_encode(wstring2utf8(g_wstrProductKey)).c_str() |
| ); |
| |
| OSVERSIONINFO VersionInfo; |
| |
| ZeroMemory( &VersionInfo, sizeof(VersionInfo) ); |
| VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo ); |
| |
| GetVersionEx( &VersionInfo ); |
| |
| fprintf( fp, |
| "<systeminfo:systeminfo xmlns:systeminfo=\"http://openoffice.org/2002/systeminfo\">\n" |
| "<systeminfo:System name=\"%s\" version=\"%d.%d\" build=\"%d\" locale=\"0x%08x\"/>\n" |
| , |
| VER_PLATFORM_WIN32_NT == VersionInfo.dwPlatformId ? "Windows NT" : "Windows", |
| VersionInfo.dwMajorVersion, VersionInfo.dwMinorVersion, |
| VersionInfo.dwBuildNumber, |
| GetUserDefaultLangID() |
| |
| ); |
| fprintf( fp, "<systeminfo:CPU type=\"x86\"/>\n" ); |
| fprintf( fp, "</systeminfo:systeminfo>\n" ); |
| |
| fseek( g_fpStackFile, 0, SEEK_SET ); |
| fcopy( g_fpStackFile, fp ); |
| |
| fseek( g_fpChecksumFile, 0, SEEK_SET ); |
| fcopy( g_fpChecksumFile, fp ); |
| |
| fprintf( fp, "</errormail:errormail>\n" ); |
| |
| fclose( fp ); |
| |
| fSuccess = TRUE; |
| |
| WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szReportFileNameA, MAX_PATH, NULL, NULL ); |
| } |
| |
| if ( !fSuccess ) |
| DeleteFile( szFileName ); |
| } |
| } |
| |
| return fSuccess; |
| } |
| |
| //*************************************************************************** |
| |
| static BOOL SaveDumpFile( HWND hwndOwner ) |
| { |
| OPENFILENAME ofn; |
| TCHAR szFileName[MAX_PATH] = TEXT(""); |
| |
| ZeroMemory( &ofn, sizeof(ofn) ); |
| ofn.lStructSize = sizeof(ofn); |
| |
| ofn.hwndOwner = hwndOwner; |
| ofn.lpstrFilter = TEXT("*.dmp\0*.dmp\0*.*\0*.*\0"); |
| ofn.lpstrFile = szFileName; |
| ofn.nMaxFile = MAX_PATH; |
| ofn.Flags = OFN_ENABLESIZING | OFN_LONGNAMES | OFN_OVERWRITEPROMPT; |
| ofn.lpstrDefExt = TEXT("dmp"); |
| |
| if ( GetSaveFileName( &ofn ) ) |
| { |
| return CopyFile( g_szDumpFileName, szFileName, FALSE ); |
| } |
| |
| |
| return FALSE; |
| } |
| |
| //*************************************************************************** |
| |
| static BOOL ScreenToClientRect( HWND hwnd, LPRECT lprc ) |
| { |
| return ScreenToClient( hwnd, (LPPOINT)&lprc->left ) && ScreenToClient( hwnd, (LPPOINT)&lprc->right ); |
| } |
| |
| static BOOL SetWindowRect( HWND hwnd, const RECT *lprc, BOOL fRepaint ) |
| { |
| return MoveWindow( hwnd, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, fRepaint ); |
| } |
| |
| #define GM_LOX 0x01 |
| #define GM_HIX 0x02 |
| #define GM_LOY 0x04 |
| #define GM_HIY 0x08 |
| |
| static BOOL SetGrowMode( HWND hwnd, DWORD dwGrowMode ) |
| { |
| return SetProp( hwnd, TEXT("GrowMode"), (HANDLE)dwGrowMode ); |
| } |
| |
| static DWORD GetGrowMode( HWND hwnd ) |
| { |
| return (DWORD)GetProp( hwnd, TEXT("GrowMode") ); |
| } |
| |
| static BOOL GrowWindow( HWND hwnd, LONG dxClient, LONG dyClient, BOOL fRepaint ) |
| { |
| DWORD dwGrowMode = GetGrowMode( hwnd ); |
| RECT rc; |
| |
| GetWindowRect( hwnd, &rc ); |
| |
| if ( dwGrowMode & GM_LOX ) |
| rc.left += dxClient; |
| if ( dwGrowMode & GM_HIX ) |
| rc.right += dxClient; |
| if ( dwGrowMode & GM_LOY ) |
| rc.top += dyClient; |
| if ( dwGrowMode & GM_HIY ) |
| rc.bottom += dyClient; |
| |
| ScreenToClientRect( GetParent( hwnd ), &rc ); |
| SetWindowRect( hwnd, &rc, fRepaint ); |
| |
| return TRUE; |
| } |
| |
| BOOL CALLBACK GrowChildWindows( |
| HWND hwnd, // handle to child window |
| LPARAM lParam // application-defined value |
| ) |
| { |
| LONG cx = (SHORT)LOWORD( lParam ); |
| LONG cy = (SHORT)HIWORD( lParam ); |
| |
| GrowWindow( hwnd, cx, cy, TRUE ); |
| |
| return TRUE; |
| } |
| |
| /* |
| BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam) |
| { |
| HFONT aFont = *((HFONT*) lParam); |
| HDC hDC = GetDC( hwndChild ); |
| SelectObject( hDC, aFont ); |
| ReleaseDC( hwndChild, hDC ); |
| return TRUE; |
| } |
| |
| void ApplySystemFont( HWND hwndDlg ) |
| { |
| NONCLIENTMETRICSA aNonClientMetrics; |
| aNonClientMetrics.cbSize = sizeof( aNonClientMetrics ); |
| if ( SystemParametersInfoA( SPI_GETNONCLIENTMETRICS, sizeof( aNonClientMetrics ), &aNonClientMetrics, 0 ) ) |
| { |
| HFONT aSysFont = CreateFontIndirectA( &aNonClientMetrics.lfMessageFont ); |
| EnumChildWindows(hwndDlg, EnumChildProc, (LPARAM) &aSysFont); |
| } |
| } |
| */ |
| |
| BOOL CALLBACK PreviewDialogProc( |
| HWND hwndDlg, |
| UINT uMsg, |
| WPARAM wParam, |
| LPARAM lParam |
| ) |
| { |
| static RECT rcClient; |
| |
| switch ( uMsg ) |
| { |
| case WM_SIZE: |
| { |
| LONG cx = LOWORD( lParam ); |
| LONG cy = HIWORD( lParam ); |
| LONG dxClient, dyClient; |
| |
| dxClient = cx - rcClient.right; |
| dyClient = cy - rcClient.bottom; |
| |
| EnumChildWindows( hwndDlg, GrowChildWindows, MAKELONG( (SHORT)dxClient, (SHORT)dyClient) ); |
| |
| GetClientRect( hwndDlg, &rcClient ); |
| } |
| break; |
| case WM_INITDIALOG: |
| { |
| GetClientRect( hwndDlg, &rcClient ); |
| SetGrowMode( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GM_HIX | GM_HIY ); |
| SetGrowMode( GetDlgItem(hwndDlg, IDOK), GM_LOX | GM_HIX | GM_LOY | GM_HIY ); |
| |
| CrashReportParams *pParams = (CrashReportParams *)lParam; |
| |
| TCHAR szBuffer[256] = TEXT(""); |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE ); |
| HWND hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT ); |
| |
| GetWindowText( hwndParent, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( hwndDlg, szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer ); |
| |
| basic_string<TCHAR> aString; |
| |
| aString.append( pParams->sTitle ); |
| aString.append( _T("\r\n\r\n") ); |
| aString.append( pParams->sComment ); |
| aString.append( _T("\r\n---------- report ----------\r\n") ); |
| |
| FILE *fp = fopen( g_szReportFileNameA, "r" ); |
| |
| if ( fp ) |
| { |
| char buf[1024]; |
| |
| while ( fgets( buf, elementsof(buf), fp ) != NULL ) |
| { |
| WCHAR bufW[1024]; |
| |
| MultiByteToWideChar( CP_UTF8, 0, buf, -1, bufW, elementsof(bufW) ); |
| |
| aString.append( bufW ); |
| } |
| |
| fclose( fp ); |
| } |
| |
| aString.append( _T("\r\n---------- stack ----------\r\n") ); |
| |
| fp = fopen( g_szDumpFileNameA, "rb" ); |
| |
| if ( fp ) |
| { |
| unsigned char buf[16]; |
| int count; |
| |
| do |
| { |
| int i; |
| |
| count = fread( buf, sizeof(buf[0]), sizeof(buf)/sizeof(buf[0]), fp ); |
| |
| for ( i = 0; i < count; i++ ) |
| { |
| TCHAR output[16]; |
| |
| _sntprintf( output, elementsof(output), _T("%02X\x20"), buf[i] ); |
| aString.append( output ); |
| } |
| for ( ; i < elementsof(buf); i++ ) |
| { |
| aString.append( _T("\x20\x20\x20") ); |
| } |
| |
| for ( i = 0; i < count; i++ ) |
| { |
| TCHAR output[2]; |
| |
| if ( (int)buf[i] >= 0x20 && (int)buf[i] <= 0x7F ) |
| output[0] = (TCHAR)buf[i]; |
| else |
| output[0] = '.'; |
| output[1] = 0; |
| aString.append( output ); |
| } |
| |
| aString.append( _T("\r\n") ); |
| |
| } while ( count ); |
| |
| fclose( fp ); |
| } |
| |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), aString.c_str() ); |
| |
| |
| SetWindowFont( GetDlgItem(hwndDlg, IDC_EDIT_PREVIEW), GetStockObject( SYSTEM_FIXED_FONT ), TRUE ); |
| } |
| return TRUE; |
| case WM_COMMAND: |
| switch ( LOWORD(wParam) ) |
| { |
| case IDOK: |
| case IDCANCEL: |
| EndDialog( hwndDlg, wParam ); |
| return TRUE; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } |
| //*************************************************************************** |
| |
| static void PreviewReport( HWND hwndParent, CrashReportParams *pParams ) |
| { |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndParent, GWL_HINSTANCE ); |
| |
| WriteReportFile( pParams ); |
| |
| DialogBoxParam( |
| hInstance, |
| MAKEINTRESOURCE(IDD_PREVIEW_FRAME), |
| hwndParent, |
| PreviewDialogProc, |
| (LPARAM)pParams |
| ); |
| |
| DeleteFileA( g_szReportFileNameA ); |
| } |
| //*************************************************************************** |
| void UpdateOptionsDialogControls( HWND hwndDlg ) |
| { |
| if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED ) |
| { |
| EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), TRUE ); |
| EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), TRUE ); |
| } |
| else |
| { |
| EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), FALSE ); |
| EnableWindow( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), FALSE ); |
| } |
| } |
| |
| //*************************************************************************** |
| |
| BOOL CALLBACK OptionsDialogProc( |
| HWND hwndDlg, |
| UINT uMsg, |
| WPARAM wParam, |
| LPARAM lParam |
| ) |
| { |
| static CrashReportParams *pParams; |
| |
| switch ( uMsg ) |
| { |
| case WM_INITDIALOG: |
| { |
| TCHAR szBuffer[1024] = TEXT(""); |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE ); |
| //HWND hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT ); |
| |
| pParams = (CrashReportParams *)lParam; |
| |
| LoadAndFormatString( hInstance, IDS_OPTIONS_CAPTION, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( hwndDlg, szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_PROXY_SETTINGS_HEADER, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_PROXY_SETTINGS), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_PROXY_SYSTEM, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_PROXY_DIRECT, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_PROXY_MANUAL, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_LABEL_PROXYSERVER, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYSERVER), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_LABEL_PROXYPORT, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_LABEL_PROXYPORT), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_OK_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDOK), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer ); |
| |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), pParams->sProxyServer.c_str() ); |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), pParams->sProxyPort.c_str() ); |
| |
| Button_SetCheck( GetDlgItem(hwndDlg, IDC_RADIO_SYSTEM + pParams->uInternetConnection), BST_CHECKED ); |
| |
| SendMessage( |
| GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION), |
| EM_SETBKGNDCOLOR, |
| (WPARAM)FALSE, |
| GetSysColor( COLOR_3DFACE ) ); |
| LoadAndFormatString( hInstance, IDS_PROXY_DESCRIPTION, szBuffer, elementsof(szBuffer) ); |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_PROXY_DESCRIPTION), szBuffer ); |
| |
| UpdateOptionsDialogControls( hwndDlg ); |
| } |
| return TRUE; |
| case WM_COMMAND: |
| switch ( LOWORD(wParam) ) |
| { |
| case IDC_RADIO_SYSTEM: |
| case IDC_RADIO_DIRECT: |
| case IDC_RADIO_MANUAL: |
| if ( BN_CLICKED == HIWORD(wParam) ) |
| UpdateOptionsDialogControls( hwndDlg ); |
| break; |
| case IDOK: |
| { |
| TCHAR szBuffer[1024]; |
| |
| Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), szBuffer, elementsof(szBuffer) ); |
| pParams->sProxyServer = szBuffer; |
| |
| Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), szBuffer, elementsof(szBuffer) ); |
| pParams->sProxyPort = szBuffer; |
| |
| if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_DIRECT) ) & BST_CHECKED ) |
| pParams->uInternetConnection = 1; |
| else if ( Button_GetCheck( GetDlgItem(hwndDlg, IDC_RADIO_MANUAL) ) & BST_CHECKED ) |
| pParams->uInternetConnection = 2; |
| else |
| pParams->uInternetConnection = 0; |
| } |
| case IDCANCEL: |
| EndDialog( hwndDlg, wParam ); |
| return TRUE; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } |
| |
| //*************************************************************************** |
| |
| static void OptionsDialog( HWND hwndParent, CrashReportParams *pParams ) |
| { |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndParent, GWL_HINSTANCE ); |
| |
| if ( IDOK == DialogBoxParam( |
| hInstance, |
| MAKEINTRESOURCE(IDD_OPTIONS_FRAME), |
| hwndParent, |
| OptionsDialogProc, |
| (LPARAM)pParams |
| ) ) |
| pParams->WriteToRegistry(); |
| |
| } |
| //*************************************************************************** |
| |
| void UpdateReportDialogControls( HWND hwndDlg ) |
| { |
| EnableWindow( |
| GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), |
| Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT)) & BST_CHECKED ? TRUE : FALSE ); |
| EnableWindow( |
| GetDlgItem(hwndDlg, IDC_LABEL_EMAIL), |
| Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT)) & BST_CHECKED ? TRUE : FALSE ); |
| } |
| |
| //*************************************************************************** |
| |
| BOOL CALLBACK ReportDialogProc( |
| HWND hwndDlg, |
| UINT uMsg, |
| WPARAM wParam, |
| LPARAM |
| ) |
| { |
| switch ( uMsg ) |
| { |
| case WM_INITDIALOG: |
| { |
| CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA ); |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE ); |
| TCHAR szBuffer[FORMATBUFSIZE]; |
| |
| LoadAndFormatString( hInstance, IDS_REPORT_INTRO, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_REPORT_INTRO), szBuffer ); |
| |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT3), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_ENTER_TITLE, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_TITLE), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_ENTER_DESCRIPTION, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_ENTER_DESCRIPTION), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_SHOW_REPORT_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_SHOW_REPORT), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_SAVE_REPORT_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), szBuffer ); |
| |
| const char *pszUserType = getenv( "STAROFFICE_USERTYPE" ); |
| if ( pszUserType ) |
| ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_SHOW ); |
| else |
| ShowWindow( GetDlgItem(hwndDlg, IDC_SAVE_REPORT), SW_HIDE ); |
| |
| LoadAndFormatString( hInstance, IDS_OPTIONS_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_OPTIONS), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_ALLOW_CONTACT, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), szBuffer ); |
| Button_SetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT), pParams->fAllowContact ? BST_CHECKED : BST_UNCHECKED ); |
| |
| LoadAndFormatString( hInstance, IDS_LABEL_EMAIL, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDC_LABEL_EMAIL), szBuffer ); |
| |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), pParams->sEmail.c_str() ); |
| |
| UpdateReportDialogControls( hwndDlg ); |
| } |
| return TRUE; |
| case WM_SHOWWINDOW: |
| if ( (BOOL)wParam ) |
| { |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE ); |
| CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA ); |
| TCHAR szBuffer[FORMATBUFSIZE]; |
| |
| LoadAndFormatString( hInstance, IDS_REPORT_CAPTION, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( GetParent(hwndDlg), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_REPORT_HEADER, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_DONOT_SEND_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer ); |
| |
| |
| ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), TRUE ); |
| ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), TRUE ); |
| ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), FALSE ); |
| |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), pParams->sTitle.c_str() ); |
| Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), pParams->sComment.c_str() ); |
| |
| /* |
| SetWindowLong( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWL_STYLE, |
| GetWindowLong( GetDlgItem(GetParent(hwndDlg),IDFINISH), GWL_STYLE) | BS_DEFPUSHBUTTON ); |
| SetWindowLong( GetDlgItem(GetParent(hwndDlg),IDBACK), GWL_STYLE, |
| GetWindowLong( GetDlgItem(GetParent(hwndDlg),IDBACK), GWL_STYLE) &~ BS_DEFPUSHBUTTON ); |
| */ |
| SetFocus( GetDlgItem(hwndDlg,IDC_EDIT_TITLE) ); |
| } |
| break; |
| case WM_COMMAND: |
| switch ( LOWORD(wParam) ) |
| { |
| case IDC_SHOW_REPORT: |
| { |
| TCHAR szBuffer[32767]; |
| |
| CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA ); |
| |
| pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndDlg, IDC_ALLOW_CONTACT) ) ? TRUE : FALSE; |
| |
| Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) ); |
| pParams->sTitle = szBuffer; |
| |
| Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) ); |
| pParams->sComment = szBuffer; |
| |
| Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) ); |
| pParams->sEmail = szBuffer; |
| |
| PreviewReport( GetParent(hwndDlg), pParams ); |
| } |
| return TRUE; |
| case IDC_SAVE_REPORT: |
| SaveDumpFile( GetParent(hwndDlg) ); |
| return TRUE; |
| case IDC_OPTIONS: |
| { |
| CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( GetParent(hwndDlg), GWL_USERDATA ); |
| OptionsDialog( GetParent(hwndDlg), pParams ); |
| } |
| return TRUE; |
| case IDC_ALLOW_CONTACT: |
| if ( BN_CLICKED == HIWORD(wParam) ) |
| UpdateReportDialogControls( hwndDlg ); |
| return TRUE; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } |
| //*************************************************************************** |
| |
| BOOL CALLBACK WelcomeDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) |
| { |
| switch ( uMsg ) |
| { |
| case WM_INITDIALOG: |
| { |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE ); |
| HWND hwndRichEdit = GetDlgItem(hwndDlg, IDC_RICHEDIT21); |
| TCHAR szBuffer[FORMATBUFSIZE]; |
| TCHAR szBuffer2[FORMATBUFSIZE]; |
| TCHAR szURL[256]; |
| TCHAR szCaption[256]; |
| |
| SendMessage( |
| hwndRichEdit, |
| EM_SETBKGNDCOLOR, |
| (WPARAM)FALSE, |
| GetSysColor( COLOR_3DFACE ) ); |
| |
| SendMessage( hwndRichEdit, EM_SETEVENTMASK, 0, ENM_LINK ); |
| SendMessage( hwndRichEdit, EM_AUTOURLDETECT, TRUE, 0 ); |
| |
| LoadAndFormatString( hInstance, IDS_WELCOME_BODY1, szBuffer, elementsof(szBuffer) ); |
| LoadAndFormatString( hInstance, IDS_WELCOME_BODY2, szBuffer2, elementsof(szBuffer2) ); |
| _tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) ); |
| LoadAndFormatString( hInstance, IDS_WELCOME_BODY3, szBuffer2, elementsof(szBuffer2) ); |
| _tcsncat( szBuffer, szBuffer2, elementsof(szBuffer) ); |
| LoadString( hInstance, IDS_PRIVACY_URL, szURL, elementsof(szURL) ); |
| _tcsncat( szBuffer, szURL, elementsof(szBuffer) ); |
| SetWindowText( hwndRichEdit, szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szCaption, elementsof(szCaption) ); |
| SetWindowText( GetParent(hwndDlg), szCaption ); |
| |
| } |
| return TRUE; |
| case WM_SHOWWINDOW: |
| if ( (BOOL)wParam ) |
| { |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE ); |
| TCHAR szBuffer[FORMATBUFSIZE]; |
| |
| LoadAndFormatString( hInstance, IDS_WELCOME_CAPTION, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( GetParent(hwndDlg), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_WELCOME_HEADER, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( GetDlgItem(GetParent(hwndDlg), IDC_HEADER), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(GetParent(hwndDlg), IDCANCEL), szBuffer ); |
| |
| ShowWindow( GetDlgItem(GetParent(hwndDlg),IDBACK), FALSE ); |
| ShowWindow( GetDlgItem(GetParent(hwndDlg),IDFINISH), FALSE ); |
| ShowWindow( GetDlgItem(GetParent(hwndDlg),IDNEXT), TRUE ); |
| |
| SetFocus( GetDlgItem(GetParent(hwndDlg),IDNEXT) ); |
| } |
| break; |
| case WM_NOTIFY: |
| { |
| LPNMHDR pnmh = (LPNMHDR)lParam; |
| |
| if ( pnmh->idFrom == IDC_RICHEDIT21 && pnmh->code == EN_LINK ) |
| { |
| ENLINK *plink = (ENLINK*)lParam; |
| |
| if ( plink->msg == WM_LBUTTONUP ) |
| { |
| TCHAR szBuffer[256]; |
| TEXTRANGE range; |
| |
| range.chrg = plink->chrg; |
| range.lpstrText = szBuffer; |
| |
| SendMessage( pnmh->hwndFrom, EM_GETTEXTRANGE, 0, (LPARAM)&range ); |
| |
| ShellExecute( hwndDlg, NULL, szBuffer, NULL, NULL, SW_SHOWDEFAULT ); |
| } |
| |
| } |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } |
| //*************************************************************************** |
| |
| BOOL CALLBACK DialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) |
| { |
| static HWND hwndPages[2] = { NULL }; |
| static int iActualPage = 0; |
| |
| switch ( uMsg ) |
| { |
| case WM_INITDIALOG: |
| { |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE ); |
| TCHAR szBuffer[FORMATBUFSIZE]; |
| |
| SetWindowLong( hwndDlg, GWL_USERDATA, (LONG)lParam ); |
| hwndPages[0] = CreateDialog( |
| hInstance, |
| MAKEINTRESOURCE(IDD_WELCOME_PAGE), |
| hwndDlg, |
| WelcomeDialogProc ); |
| |
| hwndPages[1] = CreateDialog( |
| hInstance, |
| MAKEINTRESOURCE(IDD_REPORT_PAGE), |
| hwndDlg, |
| ReportDialogProc ); |
| |
| CHARFORMAT chfmt; |
| |
| chfmt.cbSize = sizeof(chfmt); |
| chfmt.dwMask = CFM_BOLD; |
| chfmt.dwEffects = CFE_BOLD; |
| |
| SendMessage( |
| GetDlgItem(hwndDlg, IDC_HEADER), |
| EM_SETCHARFORMAT, |
| SCF_ALL, |
| (LPARAM)&chfmt ); |
| |
| LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_NEXT_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDNEXT), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_SEND_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDFINISH), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_BACK_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDBACK), szBuffer ); |
| |
| ShowWindow( hwndPages[1], SW_HIDE ); |
| ShowWindow( hwndPages[0], SW_SHOW ); |
| |
| // Let Crash Reporter window stay on top of all other windows |
| SetWindowPos( hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); |
| } |
| return FALSE; |
| case WM_CTLCOLORSTATIC: |
| return (BOOL)CreateSolidBrush(GetSysColor(COLOR_WINDOW)); |
| case WM_COMMAND: |
| switch ( LOWORD(wParam) ) |
| { |
| case IDBACK: |
| if ( iActualPage > 0 ) |
| { |
| ShowWindow( hwndPages[iActualPage], SW_HIDE ); |
| ShowWindow( hwndPages[--iActualPage], SW_SHOW ); |
| } |
| return TRUE; |
| case IDNEXT: |
| if ( iActualPage < elementsof(hwndPages) - 1 ) |
| { |
| ShowWindow( hwndPages[iActualPage], SW_HIDE ); |
| ShowWindow( hwndPages[++iActualPage], SW_SHOW ); |
| } |
| return TRUE; |
| case IDFINISH: |
| { |
| TCHAR szBuffer[32767]; |
| CrashReportParams *pParams = (CrashReportParams*)GetWindowLong( hwndDlg, GWL_USERDATA ); |
| |
| pParams->fAllowContact = Button_GetCheck( GetDlgItem(hwndPages[1], IDC_ALLOW_CONTACT) ) ? TRUE : FALSE; |
| |
| Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_TITLE), szBuffer, elementsof(szBuffer) ); |
| pParams->sTitle = szBuffer; |
| |
| Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_DESCRIPTION), szBuffer, elementsof(szBuffer) ); |
| pParams->sComment = szBuffer; |
| |
| Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_EMAIL), szBuffer, elementsof(szBuffer) ); |
| pParams->sEmail = szBuffer; |
| |
| if ( pParams->fAllowContact && !pParams->sEmail.length() ) |
| { |
| TCHAR szMessage[MAX_TEXT_BUFFER]; |
| |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_NOEMAILADDRESS, szMessage, elementsof(szMessage) ); |
| |
| MessageBox( hwndDlg, szMessage, NULL, MB_ICONERROR | MB_OK ); |
| break; // Don't end the dialog |
| } |
| else |
| { |
| pParams->WriteToRegistry(); |
| |
| WriteCommentFile( pParams->sComment.c_str() ); |
| WriteReportFile( pParams ); |
| |
| if ( !SendCrashReport( hwndDlg, *pParams ) ) |
| break; // Don't end the dialog |
| } |
| } |
| // Fallthrough !!! |
| case IDCANCEL: |
| EndDialog( hwndDlg, wParam ); |
| return TRUE; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } |
| |
| |
| |
| //***************************************************************************** |
| //* Generate MD5 checksum |
| //***************************************************************************** |
| |
| #define MAGIC_DESCRIPTION_FILLER 'x' |
| #define MAGIC_DESCRIPTION_COUNT 80 |
| |
| static void repatch_soffice_exe( void *pBuffer, size_t nBufSize ) |
| { |
| wchar_t DescriptionBuffer[MAGIC_DESCRIPTION_COUNT]; |
| |
| memset( DescriptionBuffer, 0, sizeof(DescriptionBuffer) ); |
| wcsncpy( DescriptionBuffer, g_wstrProductKey.c_str(), elementsof(DescriptionBuffer) - 1 ); |
| |
| bool bPatched = false; |
| |
| do |
| { |
| void *pFound = memchr( pBuffer, ((char *)DescriptionBuffer)[0], nBufSize ); |
| |
| if ( pFound ) |
| { |
| size_t distance = (char *)pFound - (char *)pBuffer; |
| |
| if ( nBufSize >= distance ) |
| { |
| nBufSize -= distance; |
| |
| if ( nBufSize >= sizeof(DescriptionBuffer) && |
| 0 == memcmp( pFound, DescriptionBuffer, sizeof(DescriptionBuffer) ) ) |
| { |
| for ( int i = 0; i < 80; i++ ) |
| { |
| ((wchar_t *)pFound)[i] = MAGIC_DESCRIPTION_FILLER; |
| } |
| bPatched = true; |
| } |
| else |
| { |
| pBuffer = (void *)(((char *)pFound) + 1); |
| nBufSize--; |
| } |
| } |
| else |
| nBufSize = 0; |
| } |
| else |
| nBufSize = 0; |
| } while ( !bPatched && nBufSize ); |
| } |
| |
| // Normalize executable/library images to prevent different MD5 checksums due |
| // to a different PE header date/checksum (this doesn't affect the code/data |
| // sections of a executable/library. Please see tools/source/bootstrp/md5.cxx |
| // where the same method is also used. The tool so_checksum creates the MD5 |
| // checksums during build time. You have to make sure that both methods use the |
| // same algorithm otherwise there could be problems with stack reports. |
| static void normalize_pe_image(sal_uInt8* buffer, size_t nBufferSize) |
| { |
| const int OFFSET_PE_OFFSET = 0x3c; |
| const int OFFSET_COFF_TIMEDATESTAMP = 4; |
| const int PE_SIGNATURE_SIZE = 4; |
| const int COFFHEADER_SIZE = 20; |
| const int OFFSET_PE_OPTIONALHEADER_CHECKSUM = 64; |
| |
| // Check the header part of the file buffer |
| if (buffer[0] == 'M' && buffer[1] == 'Z') |
| { |
| unsigned long PEHeaderOffset = (long)buffer[OFFSET_PE_OFFSET]; |
| if (PEHeaderOffset < nBufferSize-4) |
| { |
| if ( buffer[PEHeaderOffset] == 'P' && |
| buffer[PEHeaderOffset+1] == 'E' && |
| buffer[PEHeaderOffset+2] == 0 && |
| buffer[PEHeaderOffset+3] == 0 ) |
| { |
| PEHeaderOffset += PE_SIGNATURE_SIZE; |
| if (PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP < nBufferSize-4) |
| { |
| // Set timedatestamp and checksum fields to a normalized |
| // value to enforce the same MD5 checksum for identical |
| // Windows executables/libraries. |
| buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP] = 0; |
| buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+1] = 0; |
| buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+2] = 0; |
| buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+3] = 0; |
| } |
| |
| if (PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM < nBufferSize-4) |
| { |
| // Set checksum to a normalized value |
| buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM] = 0; |
| buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+1] = 0; |
| buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+2] = 0; |
| buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+3] = 0; |
| } |
| } |
| } |
| } |
| } |
| |
| static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen ) |
| { |
| const int MINIMAL_FILESIZE = 512; |
| |
| sal_uInt32 nBytesProcessed = 0; |
| |
| FILE *fp = fopen( filename, "rb" ); |
| |
| if ( fp ) |
| { |
| long nFileSize; |
| |
| if ( 0 == fseek( fp, 0, SEEK_END ) && -1 != (nFileSize = ftell(fp)) ) |
| { |
| rewind( fp ); |
| |
| sal_uInt8 *pBuffer = new sal_uInt8[nFileSize]; |
| size_t nBytesRead = fread( pBuffer, 1, nFileSize, fp ); |
| |
| if ( sal::static_int_cast<long>(nBytesRead) == nFileSize ) |
| { |
| if ( 0 == stricmp( GetFileName(filename).c_str(), "soffice.bin" ) ) |
| repatch_soffice_exe( pBuffer, nBytesRead ); |
| else if ( nFileSize > MINIMAL_FILESIZE ) |
| normalize_pe_image( pBuffer, nBytesRead ); |
| |
| rtlDigestError error = rtl_digest_MD5 ( |
| pBuffer, nBytesRead, |
| pChecksum, nChecksumLen ); |
| |
| if ( rtl_Digest_E_None == error ) |
| nBytesProcessed = nBytesRead; |
| } |
| |
| delete[] pBuffer; |
| } |
| |
| fclose( fp ); |
| |
| } |
| |
| return nBytesProcessed; |
| } |
| |
| #if 0 |
| static sal_uInt32 calc_md5_checksum( const char *filename, sal_uInt8 *pChecksum, sal_uInt32 nChecksumLen ) |
| { |
| sal_uInt32 nBytesProcessed = 0; |
| |
| FILE *fp = fopen( filename, "rb" ); |
| |
| if ( fp ) |
| { |
| rtlDigest digest = rtl_digest_createMD5(); |
| |
| if ( digest ) |
| { |
| size_t nBytesRead; |
| sal_uInt8 buffer[4096]; |
| rtlDigestError error = rtl_Digest_E_None; |
| |
| while ( rtl_Digest_E_None == error && |
| 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) |
| { |
| error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); |
| nBytesProcessed += nBytesRead; |
| } |
| |
| if ( rtl_Digest_E_None == error ) |
| { |
| error = rtl_digest_getMD5( digest, pChecksum, nChecksumLen ); |
| } |
| |
| if ( rtl_Digest_E_None != error ) |
| nBytesProcessed = 0; |
| |
| rtl_digest_destroyMD5( digest ); |
| } |
| |
| fclose( fp ); |
| } |
| |
| return nBytesProcessed; |
| } |
| |
| #endif |
| //*************************************************************************** |
| |
| static bool WriteStackFile( FILE *fout, hash_map< string, string >& rLibraries, DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers ) |
| { |
| bool fSuccess = false; |
| |
| if ( fout && dwProcessId && pExceptionPointers ) |
| { |
| HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId ); |
| |
| if ( IsValidHandle(hProcess) ) |
| { |
| EXCEPTION_POINTERS aExceptionPointers; |
| CONTEXT aContextRecord; |
| |
| ReadProcessMemory( |
| hProcess, |
| pExceptionPointers, |
| &aExceptionPointers, |
| sizeof(aExceptionPointers), |
| NULL ); |
| |
| ReadProcessMemory( |
| hProcess, |
| aExceptionPointers.ContextRecord, |
| &aContextRecord, |
| sizeof(aContextRecord), |
| NULL ); |
| |
| STACKFRAME frame; |
| |
| ZeroMemory( &frame, sizeof(frame) ); |
| frame.AddrPC.Offset = aContextRecord.Eip; |
| frame.AddrPC.Mode = AddrModeFlat; |
| frame.AddrFrame.Offset = aContextRecord.Ebp; |
| frame.AddrFrame.Mode = AddrModeFlat; |
| |
| BOOL bSuccess; |
| int frameNum = 0; |
| |
| SymInitialize( hProcess, NULL, TRUE ); |
| |
| fprintf( fout, "<errormail:Stack type=\"Win32\">\n" ); |
| |
| do |
| { |
| fSuccess = true; |
| |
| bSuccess = StackWalk( IMAGE_FILE_MACHINE_I386, |
| hProcess, |
| NULL, |
| &frame, |
| &aContextRecord, |
| (PREAD_PROCESS_MEMORY_ROUTINE)ReadProcessMemory, |
| SymFunctionTableAccess, |
| SymGetModuleBase, |
| NULL ); |
| |
| if ( bSuccess ) |
| { |
| // Note: ImageHelp ANSI functions do not have an A postfix while |
| // Unicode versions have a W postfix. There's no macro |
| // that depends on define UNICODE |
| |
| IMAGEHLP_MODULE moduleInfo; |
| |
| ZeroMemory( &moduleInfo, sizeof(moduleInfo) ); |
| moduleInfo.SizeOfStruct = sizeof(moduleInfo); |
| |
| if ( SymGetModuleInfo( hProcess, frame.AddrPC.Offset, &moduleInfo ) ) |
| { |
| rLibraries[ GetFileName( moduleInfo.LoadedImageName ).c_str() ] = moduleInfo.LoadedImageName; |
| |
| DWORD dwRelOffset = 0; |
| BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 256 ]; |
| PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer; |
| |
| ZeroMemory( symbolBuffer, sizeof(symbolBuffer) ); |
| pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); |
| pSymbol->MaxNameLength = 256; |
| |
| if ( SymGetSymFromAddr( hProcess, frame.AddrPC.Offset, &dwRelOffset, pSymbol ) ) |
| fprintf( fout, "<errormail:StackInfo " \ |
| "pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" ordinal=\"%s+0x%p\" name=\"%s\" path=\"%s\"/>\n", |
| frameNum, |
| frame.AddrPC.Offset, |
| frame.AddrPC.Offset - moduleInfo.BaseOfImage, |
| xml_encode(pSymbol->Name).c_str(), |
| frame.AddrPC.Offset - pSymbol->Address, |
| xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(), |
| xml_encode( GetFileDirectory( moduleInfo.LoadedImageName )).c_str() |
| ); |
| else |
| fprintf( fout, "<errormail:StackInfo " \ |
| "pos=\"%d\" ip=\"0x%p\" rel=\"0x%p\" name=\"%s\" path=\"%s\"/>\n", |
| frameNum, |
| frame.AddrPC.Offset, |
| frame.AddrPC.Offset - moduleInfo.BaseOfImage, |
| xml_encode(GetFileName( moduleInfo.LoadedImageName )).c_str(), |
| xml_encode(GetFileDirectory( moduleInfo.LoadedImageName )).c_str() |
| ); |
| } |
| else |
| fprintf( fout, "<errormail:StackInfo pos=\"%d\" ip=\"0x%p\"/>\n", |
| frameNum, |
| frame.AddrPC.Offset |
| ); |
| |
| frameNum++; |
| } |
| |
| } while ( bSuccess ); |
| |
| fprintf( fout, "</errormail:Stack>\n" ); |
| |
| SymCleanup( hProcess ); |
| |
| CloseHandle( hProcess ); |
| } |
| |
| } |
| |
| return fSuccess; |
| } |
| |
| bool WriteChecksumFile( FILE *fchksum, const hash_map< string, string >& rLibraries ) |
| { |
| bool success = false; |
| |
| if ( fchksum && rLibraries.size() ) |
| { |
| fprintf( fchksum, "<errormail:Checksums type=\"MD5\">\n" ); |
| |
| hash_map< string, string >::const_iterator iter; |
| |
| for ( iter = rLibraries.begin(); |
| iter != rLibraries.end(); |
| iter++ ) |
| { |
| sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5]; |
| sal_uInt32 nBytesProcessed = calc_md5_checksum( |
| iter->second.c_str(), |
| checksum, sizeof(checksum) ); |
| |
| if ( nBytesProcessed ) |
| { |
| fprintf( fchksum, "<errormail:Checksum sum=\"0x" ); |
| for ( int i = 0; i < sizeof(checksum); fprintf( fchksum, "%02X", checksum[i++] ) ); |
| fprintf( fchksum, "\" bytes=\"%d\" file=\"%s\"/>\n", |
| nBytesProcessed, |
| GetFileName( iter->first ).c_str() ); |
| } |
| } |
| |
| fprintf( fchksum, "</errormail:Checksums>\n" ); |
| |
| success = true; |
| } |
| |
| return success; |
| } |
| |
| //*************************************************************************** |
| |
| BOOL FindDumpFile() |
| { |
| TCHAR szFileName[MAX_PATH]; |
| |
| if ( GetCrashDataPath( szFileName ) ) |
| { |
| _tcscat( szFileName, _T("\\crashdat.dmp") ); |
| |
| HANDLE hFile = CreateFile( |
| szFileName, |
| GENERIC_READ, |
| 0, NULL, |
| OPEN_EXISTING, |
| FILE_ATTRIBUTE_NORMAL, NULL ); |
| |
| if ( hFile ) |
| { |
| CloseHandle( hFile ); |
| |
| WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL ); |
| _tcscpy( g_szDumpFileName, szFileName ); |
| |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| BOOL WriteDumpFile( DWORD dwProcessId, PEXCEPTION_POINTERS pExceptionPointers, DWORD dwThreadId ) |
| { |
| BOOL fSuccess = FALSE; |
| PMINIDUMP_EXCEPTION_INFORMATION lpExceptionParam = NULL; |
| MINIDUMP_EXCEPTION_INFORMATION ExceptionParam; |
| |
| HMODULE hDbgHelp = LoadLibrary( _T("DBGHELP.DLL" ) ); |
| MiniDumpWriteDump_PROC pMiniDumpWriteDump = NULL; |
| |
| if ( hDbgHelp ) |
| { |
| pMiniDumpWriteDump = (MiniDumpWriteDump_PROC)GetProcAddress( hDbgHelp, "MiniDumpWriteDump" ); |
| |
| if ( !pMiniDumpWriteDump ) |
| { |
| FreeLibrary( hDbgHelp ); |
| return false; |
| } |
| } |
| |
| if ( !pMiniDumpWriteDump ) |
| return false; |
| |
| HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwProcessId ); |
| |
| if ( IsValidHandle(hProcess) ) |
| { |
| TCHAR szTempPath[MAX_PATH]; |
| |
| // if ( GetTempPath( elementsof(szTempPath), szTempPath ) ) |
| if ( GetCrashDataPath( szTempPath ) ) |
| { |
| TCHAR szFileName[MAX_PATH]; |
| |
| // if ( GetTempFileName( szTempPath, TEXT("DMP"), 0, szFileName ) ) |
| _tcscpy( szFileName, szTempPath ); |
| _tcscat( szFileName, _T("\\crashdat.dmp") ); |
| { |
| HANDLE hFile = CreateFile( |
| szFileName, |
| GENERIC_READ | GENERIC_WRITE, |
| 0, NULL, |
| // OPEN_EXISTING, |
| CREATE_ALWAYS, |
| FILE_ATTRIBUTE_NORMAL, NULL ); |
| |
| if ( hFile ) |
| { |
| if ( pExceptionPointers && dwThreadId ) |
| { |
| ExceptionParam.ThreadId = dwThreadId; |
| ExceptionParam.ExceptionPointers = pExceptionPointers; |
| ExceptionParam.ClientPointers = TRUE; |
| |
| EXCEPTION_POINTERS aExceptionPointers; |
| EXCEPTION_RECORD aExceptionRecord; |
| |
| ReadProcessMemory( |
| hProcess, |
| pExceptionPointers, |
| &aExceptionPointers, |
| sizeof(aExceptionPointers), |
| NULL ); |
| |
| |
| ReadProcessMemory( |
| hProcess, |
| aExceptionPointers.ExceptionRecord, |
| &aExceptionRecord, |
| sizeof(aExceptionRecord), |
| NULL ); |
| |
| g_dwExceptionCode = aExceptionRecord.ExceptionCode; |
| |
| lpExceptionParam = &ExceptionParam; |
| } |
| |
| fSuccess = pMiniDumpWriteDump( hProcess, dwProcessId, hFile, MiniDumpNormal, lpExceptionParam, NULL, NULL ); |
| |
| CloseHandle( hFile ); |
| |
| WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szDumpFileNameA, MAX_PATH, NULL, NULL ); |
| _tcscpy( g_szDumpFileName, szFileName ); |
| } |
| |
| if ( !fSuccess ) |
| DeleteFile( szFileName ); |
| } |
| } |
| |
| CloseHandle( hProcess ); |
| } |
| |
| FreeLibrary( hDbgHelp ); |
| |
| return fSuccess; |
| } |
| |
| //*************************************************************************** |
| |
| static DWORD FindProcessForImage( LPCTSTR lpImagePath ) |
| { |
| DWORD dwProcessId = 0; |
| DWORD aProcesses[1024]; |
| DWORD dwSize = 0; |
| TCHAR szShortImagePath[MAX_PATH]; |
| |
| if ( GetShortPathName( lpImagePath, szShortImagePath, elementsof(szShortImagePath) ) && |
| EnumProcesses( aProcesses, sizeof(aProcesses), &dwSize ) ) |
| { |
| unsigned nProcesses = dwSize / sizeof(aProcesses[0]); |
| |
| for ( unsigned i = 0; !dwProcessId && i < nProcesses; i++ ) |
| { |
| HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i] ); |
| |
| if ( IsValidHandle(hProcess) ) |
| { |
| TCHAR szModulePath[MAX_PATH+1]; |
| |
| if ( GetModuleFileNameEx( hProcess, NULL, szModulePath, MAX_PATH ) ) |
| { |
| TCHAR szShortModulePath[MAX_PATH]; |
| |
| if ( GetShortPathName( szModulePath, szShortModulePath, elementsof(szShortModulePath) ) ) |
| { |
| if ( 0 == _tcsicmp( szShortModulePath, szShortImagePath ) ) |
| dwProcessId = aProcesses[i]; |
| } |
| } |
| |
| CloseHandle( hProcess ); |
| } |
| } |
| } |
| |
| return dwProcessId; |
| } |
| //*************************************************************************** |
| |
| static bool ParseCommandArgs( LPDWORD pdwProcessId, PEXCEPTION_POINTERS* ppException, LPDWORD pdwThreadId ) |
| { |
| int argc = __argc; |
| #ifdef __MINGW32__ |
| #ifdef _UNICODE |
| TCHAR **argv = reinterpret_cast<TCHAR **>(alloca((argc+1)*sizeof(WCHAR*))); |
| int *sizes = reinterpret_cast<int *>(alloca(argc*sizeof(int))); |
| int argsize=0; |
| char **ptr; |
| int i; |
| ptr=__argv; |
| for (i = 0; i < argc; ++i) |
| { |
| sizes[i]=MultiByteToWideChar(CP_ACP, 0, *ptr, -1, NULL, 0); |
| argsize+=sizes[i]+1; |
| ++ptr; |
| } |
| ++argsize; |
| TCHAR *args = reinterpret_cast<TCHAR *>(alloca(argsize*sizeof(WCHAR))); |
| ptr=__argv; |
| TCHAR *cptr=args; |
| for (i = 0; i < argc; ++i) |
| { |
| argv[i]=cptr; |
| MultiByteToWideChar( CP_ACP, 0, *ptr, -1, cptr, sizes[i] ); |
| ++ptr; |
| cptr+=sizes[i]; |
| *cptr=0; |
| ++cptr; |
| } |
| argv[i]=cptr; |
| *cptr=0; |
| #else |
| TCHAR **argv = __argv; |
| #endif |
| #else |
| TCHAR **argv = __targv; |
| #endif |
| bool bSuccess = true; |
| |
| for ( int argn = 1; bSuccess && argn < argc; argn++ ) |
| { |
| if ( 0 == _tcsicmp( argv[argn], _T("-h") ) || |
| 0 == _tcsicmp( argv[argn], _T("/h") ) || |
| 0 == _tcsicmp( argv[argn], _T("-?") ) || |
| 0 == _tcsicmp( argv[argn], _T("/?") ) || |
| 0 == _tcsicmp( argv[argn], _T("/help") ) || |
| 0 == _tcsicmp( argv[argn], _T("-help") ) || |
| 0 == _tcsicmp( argv[argn], _T("--help") ) |
| ) |
| { |
| HINSTANCE hInstance = GetModuleHandle(NULL); |
| TCHAR szUsage[FORMATBUFSIZE]; |
| TCHAR szProcess[FORMATBUFSIZE]; |
| TCHAR szProcessDescription[FORMATBUFSIZE]; |
| TCHAR szHelpDescription[FORMATBUFSIZE]; |
| |
| LoadAndFormatString( hInstance, IDS_MSG_CMDLINE_USAGE, szUsage, elementsof(szUsage) ); |
| LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID, szProcess, elementsof(szProcess) ); |
| LoadAndFormatString( hInstance, IDS_MSG_PARAM_PROCESSID_DESCRIPTION, szProcessDescription, elementsof(szProcessDescription) ); |
| LoadAndFormatString( hInstance, IDS_MSG_PARAM_HELP_DESCRIPTION, szHelpDescription, elementsof(szHelpDescription) ); |
| |
| _tprintf( |
| TEXT("\n%s: crashrep %s\n\n") |
| TEXT("/?, -h[elp] %s\n\n") |
| TEXT("%-20s %s\n\n"), |
| szUsage, szProcess, szHelpDescription, szProcess, szProcessDescription |
| ); |
| |
| return true; |
| } |
| else if ( 0 == _tcsicmp( argv[argn], _T("-p") ) || |
| 0 == _tcsicmp( argv[argn], _T("/p") ) ) |
| { |
| if ( ++argn < argc ) |
| *pdwProcessId = _tcstoul( argv[argn], NULL, 0 ); |
| else |
| bSuccess = false; |
| } |
| else if ( 0 == _tcsicmp( argv[argn], _T("-excp") ) || |
| 0 == _tcsicmp( argv[argn], _T("/excp") ) ) |
| { |
| if ( ++argn < argc ) |
| *ppException = (PEXCEPTION_POINTERS)_tcstoul( argv[argn], NULL, 0 ); |
| else |
| bSuccess = false; |
| } |
| else if ( 0 == _tcsicmp( argv[argn], _T("-t") ) || |
| 0 == _tcsicmp( argv[argn], _T("/t") ) ) |
| { |
| if ( ++argn < argc ) |
| *pdwThreadId = _tcstoul( argv[argn], NULL, 0 ); |
| else |
| bSuccess = false; |
| } |
| else if ( 0 == _tcsicmp( argv[argn], _T("-noui") ) || |
| 0 == _tcsicmp( argv[argn], _T("/noui") ) ) |
| { |
| g_bNoUserInterface = true; |
| } |
| else if ( 0 == _tcsicmp( argv[argn], _T("-send") ) || |
| 0 == _tcsicmp( argv[argn], _T("/send") ) ) |
| { |
| g_bSendReport = true; |
| } |
| else if ( 0 == _tcsicmp( argv[argn], _T("-load") ) || |
| 0 == _tcsicmp( argv[argn], _T("/load") ) ) |
| { |
| g_bLoadReport = true; |
| } |
| else // treat parameter as image path |
| { |
| TCHAR szImagePath[MAX_PATH]; |
| LPTSTR lpImageName; |
| |
| if ( GetFullPathName( argv[argn], MAX_PATH, szImagePath, &lpImageName ) ) |
| { |
| DWORD dwProcessId = FindProcessForImage( szImagePath ); |
| |
| if ( dwProcessId ) |
| *pdwProcessId = dwProcessId; |
| else |
| bSuccess = false; |
| } |
| } |
| } |
| |
| if ( !*pdwProcessId && !g_bLoadReport ) |
| { |
| TCHAR szImagePath[MAX_PATH]; |
| LPTSTR lpImageName; |
| |
| if ( GetFullPathName( TEXT("soffice.exe"), MAX_PATH, szImagePath, &lpImageName ) ) |
| { |
| DWORD dwProcessId = FindProcessForImage( szImagePath ); |
| |
| if ( dwProcessId ) |
| *pdwProcessId = dwProcessId; |
| else |
| bSuccess = false; |
| } |
| } |
| |
| return bSuccess; |
| } |
| |
| //*************************************************************************** |
| |
| BOOL WriteCommentFile( LPCTSTR lpComment ) |
| { |
| BOOL fSuccess = FALSE; |
| TCHAR szTempPath[MAX_PATH]; |
| |
| if ( GetTempPath( elementsof(szTempPath), szTempPath ) ) |
| { |
| TCHAR szFileName[MAX_PATH]; |
| |
| if ( GetTempFileName( szTempPath, TEXT("CMT"), 0, szFileName ) ) |
| { |
| HANDLE hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); |
| |
| if ( hFile ) |
| { |
| DWORD dwBytesWritten; |
| |
| int needed = WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, NULL, 0, NULL, NULL ); |
| if ( needed ) |
| { |
| char *lpCommentUTF8 = (char *)alloca( needed ); |
| WideCharToMultiByte( CP_UTF8, 0, lpComment, -1, lpCommentUTF8, needed, NULL, NULL ); |
| fSuccess = WriteFile( hFile, lpCommentUTF8, strlen(lpCommentUTF8), &dwBytesWritten, NULL ); |
| } |
| else |
| fSuccess = TRUE; |
| |
| |
| CloseHandle( hFile ); |
| |
| WideCharToMultiByte( CP_ACP, 0, szFileName, -1, g_szCommentFileNameA, MAX_PATH, NULL, NULL ); |
| } |
| |
| if ( !fSuccess ) |
| DeleteFile( szFileName ); |
| } |
| } |
| |
| return fSuccess; |
| } |
| |
| //*************************************************************************** |
| |
| static int _tsetenv( const _TCHAR *lpVar, const _TCHAR *lpValue ) |
| { |
| if ( !lpValue ) |
| lpValue = _T(""); |
| |
| _TCHAR *envstr = (TCHAR *)alloca( (_tcslen( lpVar ) + _tcslen( lpValue ) + 2) * sizeof(_TCHAR) ); |
| |
| _tcscpy( envstr, lpVar ); |
| _tcscat( envstr, _T("=") ); |
| _tcscat( envstr, lpValue ); |
| |
| return _tputenv( envstr ); |
| } |
| |
| static bool read_line( FILE *fp, string& rLine ) |
| { |
| char szBuffer[1024]; |
| bool bSuccess = false; |
| bool bEOL = false; |
| string line; |
| |
| |
| while ( !bEOL && fgets( szBuffer, sizeof(szBuffer), fp ) ) |
| { |
| int len = strlen(szBuffer); |
| |
| bSuccess = true; |
| |
| while ( len && szBuffer[len - 1] == '\n' ) |
| { |
| szBuffer[--len] = 0; |
| bEOL = true; |
| } |
| |
| line.append( szBuffer ); |
| } |
| |
| rLine = line; |
| return bSuccess; |
| } |
| |
| static string get_script_string( const char *pFileName, const char *pKeyName ) |
| { |
| FILE *fp = fopen( pFileName, "rt" ); |
| string retValue; |
| |
| if ( fp ) |
| { |
| string line; |
| string section; |
| |
| while ( read_line( fp, line ) ) |
| { |
| line = trim_string( line ); |
| |
| |
| string::size_type iEqualSign = line.find( '=', 0 ); |
| |
| if ( iEqualSign != string::npos ) |
| { |
| string keyname = line.substr( 0, iEqualSign ); |
| keyname = trim_string( keyname ); |
| |
| string value = line.substr( sal::static_int_cast<string::size_type>(iEqualSign + 1) ); |
| value = trim_string( value ); |
| |
| if ( value.length() && '\"' == value[0] ) |
| { |
| value.erase( 0, 1 ); |
| |
| string::size_type iQuotes = value.find( '"', 0 ); |
| |
| if ( iQuotes != string::npos ) |
| value.erase( iQuotes ); |
| } |
| |
| if ( 0 == stricmp( keyname.c_str(), pKeyName ) ) |
| { |
| retValue = value; |
| break; |
| } |
| } |
| } |
| |
| fclose( fp ); |
| } |
| |
| return retValue; |
| } |
| |
| static bool ReadBootstrapParams( CrashReportParams &rParams ) |
| { |
| TCHAR szBuffer[256] = TEXT(""); |
| TCHAR szModuleName[MAX_PATH]; |
| TCHAR szModuleVersionName[MAX_PATH]; |
| TCHAR szDrive[_MAX_DRIVE]; |
| TCHAR szDir[_MAX_DIR]; |
| TCHAR szFName[_MAX_FNAME]; |
| TCHAR szExt[_MAX_EXT]; |
| TCHAR szReportServer[MAX_HOSTNAME]; |
| TCHAR szReportPort[256]; |
| bool bSuccess = false; |
| |
| GetModuleFileName( NULL, szModuleName, MAX_PATH ); |
| _tsplitpath( szModuleName, szDrive, szDir, szFName, szExt ); |
| _tmakepath( szModuleName, szDrive, szDir, _T("bootstrap"), _T(".ini") ); |
| _tmakepath( szModuleVersionName, szDrive, szDir, _T("version"), _T(".ini") ); |
| |
| if ( |
| GetPrivateProfileString( |
| TEXT("Bootstrap"), |
| TEXT("ProductKey"), |
| TEXT("OpenOffice.org"), |
| szBuffer, |
| elementsof(szBuffer), |
| szModuleName ) |
| ) |
| { |
| TCHAR *pVersion = _tcschr( szBuffer, ' ' ); |
| |
| g_wstrProductKey = szBuffer; |
| |
| if ( pVersion ) |
| { |
| *pVersion = 0; |
| pVersion++; |
| } |
| else |
| pVersion = TEXT(""); |
| |
| if ( !_tgetenv( _T("PRODUCTNAME") ) ) |
| { |
| _tsetenv( TEXT("PRODUCTNAME"), szBuffer ); |
| } |
| if ( !_tgetenv( _T("PRODUCTVERSION") ) ) |
| _tsetenv( TEXT("PRODUCTVERSION"), pVersion ); |
| } |
| |
| GetPrivateProfileString( |
| TEXT("Version"), |
| TEXT("buildid"), |
| TEXT("unknown"), |
| g_szBuildId, elementsof(g_szBuildId), |
| szModuleVersionName ); |
| |
| g_strDefaultLanguage = get_script_string( "instdb.inf", "DefaultLanguage" ); |
| |
| if ( GetPrivateProfileString( |
| TEXT("ErrorReport"), |
| TEXT("ErrorReportPort"), |
| TEXT("80"), |
| szReportPort, elementsof(szReportPort), |
| szModuleName |
| ) ) |
| { |
| TCHAR *endptr = NULL; |
| |
| unsigned short uReportPort = (unsigned short)_tcstoul( szReportPort, &endptr, 10 ); |
| if ( uReportPort ) |
| g_uReportPort = uReportPort; |
| } |
| |
| if ( GetPrivateProfileString( |
| TEXT("ErrorReport"), |
| TEXT("ErrorReportServer"), |
| TEXT(""), |
| szReportServer, elementsof(szReportServer), |
| szModuleName |
| ) ) |
| { |
| bSuccess = 0 != WideCharToMultiByte( CP_ACP, 0, szReportServer, -1, g_szReportServerA, elementsof(g_szReportServerA), NULL, NULL ); |
| } |
| |
| LPCTSTR lpEnvString; |
| |
| if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYSERVER") )) ) |
| rParams.sProxyServer = lpEnvString; |
| |
| if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_PROXYPORT") )) ) |
| rParams.sProxyPort = lpEnvString; |
| |
| if ( 0 != (lpEnvString = _tgetenv( _T("ERRORREPORT_SENDERADDRESS") )) ) |
| rParams.sEmail = lpEnvString; |
| |
| return bSuccess; |
| } |
| |
| //*************************************************************************** |
| |
| bool SendHTTPRequest( |
| FILE *fp, |
| const char *pszServer, |
| unsigned short uPort = 80, |
| const char *pszProxyServer = NULL, |
| unsigned short uProxyPort = 8080 ) |
| { |
| bool success = false; |
| |
| struct hostent *hp; |
| |
| if ( pszProxyServer ) |
| hp = gethostbyname( pszProxyServer ); |
| else |
| hp = gethostbyname( pszServer ); |
| |
| if ( hp ) |
| { |
| SOCKET s = socket( AF_INET, SOCK_STREAM, 0 ); |
| |
| if ( s ) |
| { |
| struct sockaddr_in address; |
| |
| memcpy(&(address.sin_addr.s_addr), *(hp->h_addr_list),sizeof(struct in_addr)); |
| address.sin_family = AF_INET; |
| |
| if ( pszProxyServer ) |
| address.sin_port = ntohs( uProxyPort ); |
| else |
| address.sin_port = ntohs( uPort ); |
| |
| if ( 0 == connect( s, (struct sockaddr *)&address, sizeof(struct sockaddr_in)) ) |
| { |
| fseek( fp, 0, SEEK_END ); |
| size_t length = ftell( fp ); |
| fseek( fp, 0, SEEK_SET ); |
| |
| char buffer[2048]; |
| |
| if ( pszProxyServer ) |
| sprintf( buffer, |
| "POST http://%s:%d/soap/servlet/rpcrouter HTTP/1.0\r\n" |
| "Content-Type: text/xml; charset=\"utf-8\"\r\n" |
| "Content-Length: %d\r\n" |
| "SOAPAction: \"\"\r\n\r\n", |
| pszServer, |
| uPort, |
| length |
| ); |
| else |
| sprintf( buffer, |
| "POST /soap/servlet/rpcrouter HTTP/1.0\r\n" |
| "Content-Type: text/xml; charset=\"utf-8\"\r\n" |
| "Content-Length: %d\r\n" |
| "SOAPAction: \"\"\r\n\r\n", |
| length |
| ); |
| |
| if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) ) |
| { |
| size_t nBytes; |
| |
| do |
| { |
| nBytes = fread( buffer, 1, sizeof(buffer), fp ); |
| |
| if ( nBytes ) |
| success = SOCKET_ERROR != send( s, buffer, nBytes, 0 ); |
| } while( nBytes && success ); |
| |
| if ( success ) |
| { |
| memset( buffer, 0, sizeof(buffer) ); |
| success = SOCKET_ERROR != recv( s, buffer, sizeof(buffer), 0 ); |
| if ( success ) |
| { |
| char szHTTPSignature[sizeof(buffer)] = ""; |
| unsigned uHTTPReturnCode = 0; |
| |
| sscanf( buffer, "%s %d ", szHTTPSignature, &uHTTPReturnCode ); |
| success = uHTTPReturnCode == 200; |
| } |
| } |
| } |
| |
| } |
| |
| closesocket( s ); |
| } |
| } |
| |
| return success; |
| } |
| |
| //*************************************************************************** |
| |
| static void WriteSOAPRequest( FILE *fp ) |
| { |
| fprintf( fp, |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" |
| "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" |
| "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"\n" |
| "xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\"\n" |
| "xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\"\n" |
| "xmlns:rds=\"urn:ReportDataService\"\n" |
| "xmlns:apache=\"http://xml.apache.org/xml-soap\"\n" |
| "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" |
| "<SOAP-ENV:Body>\n" |
| ); |
| |
| fprintf( fp, "<rds:submitReport>\n" ); |
| fprintf( fp, "<body xsi:type=\"xsd:string\">This is an autogenerated crash report mail.</body>\n" ); |
| fprintf( fp, "<hash xsi:type=\"apache:Map\">\n" ); |
| |
| FILE *fpin = fopen( g_szReportFileNameA, "r" ); |
| if ( fpin ) |
| { |
| fprintf( fp, |
| "<item>\n" |
| "<key xsi:type=\"xsd:string\">reportmail.xml</key>\n" |
| "<value xsi:type=\"xsd:string\"><![CDATA[" ); |
| fcopy( fpin, fp ); |
| fprintf( fp, "]]></value></item>\n" ); |
| fclose( fpin ); |
| } |
| |
| fpin = fopen( g_szCommentFileNameA, "r" ); |
| if ( fpin ) |
| { |
| fprintf( fp, |
| "<item>\n" |
| "<key xsi:type=\"xsd:string\">description.txt</key>\n" |
| "<value xsi:type=\"xsd:string\"><![CDATA[" ); |
| fcopy( fpin, fp ); |
| fprintf( fp, "]]></value></item>\n" ); |
| fclose( fpin ); |
| }; |
| |
| |
| fpin = fopen( g_szDumpFileNameA, "rb" ); |
| if ( fpin ) |
| { |
| FILE *fptemp = _tmpfile(); |
| |
| if ( fptemp ) |
| { |
| if ( base64_encode( fpin, fptemp ) ) |
| { |
| fseek( fptemp, 0, SEEK_SET ); |
| fprintf( fp, |
| "<item>\n" |
| "<key xsi:type=\"xsd:string\">user.dmp</key>\n" |
| "<value xsi:type=\"xsd:string\">" ); |
| fcopy( fptemp, fp ); |
| fprintf( fp, "</value></item>\n" ); |
| } |
| fclose( fptemp ); |
| } |
| fclose( fpin ); |
| } |
| |
| fprintf( fp, |
| "</hash>\n" |
| "</rds:submitReport>\n" |
| "</SOAP-ENV:Body>\n" |
| "</SOAP-ENV:Envelope>\n" |
| ); |
| } |
| |
| //*************************************************************************** |
| |
| struct RequestParams |
| { |
| bool success; |
| FILE *fpin; |
| const char *lpServer; |
| unsigned short uPort; |
| const char *lpProxyServer; |
| unsigned short uProxyPort; |
| HWND hwndStatus; |
| }; |
| |
| void _cdecl SendingThread( void *lpArgs ) |
| { |
| RequestParams *pParams = (RequestParams *)lpArgs; |
| |
| pParams->success = SendHTTPRequest( pParams->fpin, pParams->lpServer, pParams->uPort, pParams->lpProxyServer, pParams->uProxyPort ); |
| |
| PostMessage( pParams->hwndStatus, WM_COMMAND, IDOK, 0 ); |
| } |
| |
| //*************************************************************************** |
| |
| BOOL CALLBACK SendingStatusDialogProc( |
| HWND hwndDlg, |
| UINT uMsg, |
| WPARAM wParam, |
| LPARAM lParam |
| ) |
| { |
| static RequestParams *pRequest = NULL; |
| static HANDLE hSendingThread = NULL; |
| |
| switch ( uMsg ) |
| { |
| case WM_INITDIALOG: |
| { |
| TCHAR szBuffer[1024] = TEXT(""); |
| HINSTANCE hInstance = (HINSTANCE)GetWindowLong( hwndDlg, GWL_HINSTANCE ); |
| //HWND hwndParent = (HWND)GetWindowLong( hwndDlg, GWL_HWNDPARENT ); |
| |
| pRequest = (RequestParams *)lParam; |
| |
| LoadAndFormatString( hInstance, IDS_SENDING_REPORT_HEADER, szBuffer, elementsof(szBuffer) ); |
| SetWindowText( hwndDlg, szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_SENDING_REPORT_STATUS, szBuffer, elementsof(szBuffer) ); |
| Static_SetText( GetDlgItem(hwndDlg, IDC_SENDING_REPORT_STATUS), szBuffer ); |
| |
| LoadAndFormatString( hInstance, IDS_CANCEL_BUTTON, szBuffer, elementsof(szBuffer) ); |
| Button_SetText( GetDlgItem(hwndDlg, IDCANCEL), szBuffer ); |
| |
| pRequest->hwndStatus = hwndDlg; |
| |
| hSendingThread = (HANDLE)_beginthread( SendingThread, 0, pRequest ); |
| } |
| return TRUE; |
| case WM_COMMAND: |
| switch ( LOWORD(wParam) ) |
| { |
| case IDCANCEL: |
| TerminateThread( hSendingThread, 0 ); |
| case IDOK: |
| WaitForSingleObject( hSendingThread, INFINITE ); |
| CloseHandle( hSendingThread ); |
| EndDialog( hwndDlg, wParam ); |
| return TRUE; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return FALSE; |
| } |
| |
| //*************************************************************************** |
| |
| bool SendCrashReport( HWND hwndParent, const CrashReportParams &rParams ) |
| { |
| bool success = false; |
| char szProxyServer[1024] = ""; |
| unsigned short uProxyPort = 8080; |
| TCHAR *endptr = NULL; |
| |
| switch ( rParams.uInternetConnection ) |
| { |
| case 2: |
| { |
| WideCharToMultiByte( |
| CP_ACP, 0, rParams.sProxyServer.c_str(), -1, |
| szProxyServer, sizeof(szProxyServer), NULL, NULL ); |
| uProxyPort = (unsigned short)_tcstoul( rParams.sProxyPort.c_str(), &endptr, 10 ); |
| } |
| break; |
| case 0: |
| { |
| DWORD dwProxyEnable = 0; |
| |
| RegReadValue( HKEY_CURRENT_USER, |
| TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), |
| TEXT("ProxyEnable"), |
| &dwProxyEnable, |
| sizeof(dwProxyEnable) ); |
| |
| if ( dwProxyEnable ) |
| { |
| TCHAR tszProxyServers[1024] = TEXT(""); |
| |
| if ( ERROR_SUCCESS == RegReadValue( HKEY_CURRENT_USER, |
| TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"), TEXT("ProxyServer"), |
| tszProxyServers, |
| sizeof(tszProxyServers) ) ) |
| { |
| TCHAR *lpHttpStart = _tcsstr( tszProxyServers, TEXT("http=") ); |
| |
| if ( lpHttpStart ) |
| lpHttpStart += 5; |
| else |
| lpHttpStart = tszProxyServers; |
| |
| TCHAR *lpHttpEnd = _tcschr( lpHttpStart, ';' ); |
| |
| if ( lpHttpEnd ) |
| *lpHttpEnd = 0; |
| |
| char szHTTPProxyServer[1024] = ""; |
| WideCharToMultiByte( CP_ACP, 0, lpHttpStart, -1, szHTTPProxyServer, sizeof(szHTTPProxyServer), NULL, NULL ); |
| |
| char *lpColon = strchr( szHTTPProxyServer, ':' ); |
| |
| if ( lpColon ) |
| { |
| char *endptr = NULL; |
| |
| *lpColon = 0; |
| uProxyPort = (unsigned short)strtoul( lpColon + 1, &endptr, 10 ); |
| } |
| else |
| uProxyPort = 8080; |
| |
| strcpy( szProxyServer, szHTTPProxyServer ); |
| |
| } |
| } |
| } |
| break; |
| default: |
| case 1: |
| break; |
| } |
| |
| FILE *fptemp = _tmpfile(); |
| if ( fptemp ) |
| { |
| RequestParams request; |
| |
| request.success = false; |
| request.fpin = fptemp; |
| request.lpServer = REPORT_SERVER; |
| request.uPort = REPORT_PORT; |
| request.lpProxyServer = szProxyServer[0] ? szProxyServer : NULL; |
| request.uProxyPort = uProxyPort; |
| request.hwndStatus = NULL; |
| |
| WriteSOAPRequest( fptemp ); |
| fseek( fptemp, 0, SEEK_SET ); |
| |
| if ( hwndParent ) |
| { |
| int retid = DialogBoxParam( |
| GetModuleHandle(NULL), |
| MAKEINTRESOURCE(IDD_SENDING_STATUS), |
| hwndParent, |
| SendingStatusDialogProc, |
| (LPARAM)&request |
| ); |
| |
| success = request.success; |
| |
| if ( IDOK == retid ) |
| { |
| if ( !success ) |
| { |
| TCHAR szMessage[1024]; |
| |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) ); |
| |
| MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK ); |
| } |
| else |
| { |
| TCHAR szMessage[1024]; |
| TCHAR szTitle[1024]; |
| |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) ); |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_HEADER, szTitle, elementsof(szTitle) ); |
| |
| MessageBox( hwndParent, szMessage, szTitle, MB_ICONINFORMATION | MB_OK ); |
| } |
| } |
| |
| } |
| else |
| { |
| HANDLE hSendingThread = (HANDLE)_beginthread( SendingThread, 0, (void *)&request ); |
| |
| WaitForSingleObject( hSendingThread, INFINITE ); |
| |
| success = request.success; |
| if ( !success ) |
| { |
| TCHAR szMessage[1024]; |
| |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_PROXY, szMessage, elementsof(szMessage) ); |
| _ftprintf( stderr, _T("ERROR: %s\n"), szMessage ); |
| } |
| else |
| { |
| TCHAR szMessage[1024]; |
| |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_SENDING_REPORT_STATUS_FINISHED, szMessage, elementsof(szMessage) ); |
| |
| _ftprintf( stderr, _T("SUCCESS: %s\n"), szMessage ); |
| } |
| } |
| fclose( fptemp ); |
| } |
| else |
| { |
| TCHAR szMessage[1024]; |
| |
| LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_DISK_FULL, szMessage, elementsof(szMessage) ); |
| |
| if ( hwndParent ) |
| MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK ); |
| else |
| _ftprintf( stderr, _T("ERROR: %s\n"), szMessage ); |
| } |
| |
| return success; |
| } |
| |
| //*************************************************************************** |
| |
| #ifdef __MINGW32__ |
| int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR /*lpCmdLine*/, int ) |
| #else |
| int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR /*lpCmdLine*/, int ) |
| #endif |
| { |
| int exitcode = -1; |
| int argc = __argc; |
| |
| #ifdef __MINGW32__ |
| char **argv = __argv; |
| #else |
| #ifdef _UNICODE |
| char **argv = new char *[argc + 1]; |
| |
| for ( int argn = 0; argn < argc; argn++ ) |
| { |
| int nBytes = WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, NULL, 0, NULL, NULL ); |
| argv[argn] = new char[nBytes]; |
| WideCharToMultiByte( CP_ACP, 0, __targv[argn], -1, argv[argn], nBytes, NULL, NULL ); |
| } |
| argv[argc] = NULL; |
| #else |
| char **argv = __targv; |
| #endif |
| #endif |
| |
| osl_setCommandArgs( argc, argv ); |
| |
| PEXCEPTION_POINTERS pExceptionPointers = NULL; |
| DWORD dwProcessId = 0; |
| DWORD dwThreadId = 0; |
| |
| WSADATA wsaData; |
| WORD wVersionRequested; |
| |
| wVersionRequested = MAKEWORD(1, 1); |
| WSAStartup(wVersionRequested, &wsaData); |
| |
| CrashReportParams Params; |
| |
| Params.ReadFromRegistry(); |
| Params.ReadFromEnvironment(); |
| |
| if ( ReadBootstrapParams( Params ) && |
| ParseCommandArgs( &dwProcessId, &pExceptionPointers, &dwThreadId ) ) |
| { |
| bool bGotDumpFile; |
| |
| if ( g_bLoadReport ) |
| bGotDumpFile = FindDumpFile(); |
| else |
| bGotDumpFile = WriteDumpFile( dwProcessId, pExceptionPointers, dwThreadId ); |
| |
| if( bGotDumpFile ) |
| { |
| hash_map< string, string > aLibraries; |
| |
| if ( g_bLoadReport ) |
| { |
| g_fpStackFile = _open_reportfile( _T(".stk"), _T("rb") ); |
| g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("rb") ); |
| } |
| else |
| { |
| if ( g_bSendReport ) |
| { |
| g_fpStackFile = _tmpfile(); |
| g_fpChecksumFile = _tmpfile(); |
| } |
| else |
| { |
| g_fpStackFile = _open_reportfile( _T(".stk"), _T("w+b") ); |
| g_fpChecksumFile = _open_reportfile( _T(".chk"), _T("w+b") ); |
| |
| FILE *fpUnsent = _open_reportfile( _T(".lck"), _T("w+b") ); |
| if ( fpUnsent ) |
| { |
| fprintf( fpUnsent, "Unsent\r\n" ); |
| fclose( fpUnsent ); |
| } |
| } |
| |
| WriteStackFile( g_fpStackFile, aLibraries, dwProcessId, pExceptionPointers ); |
| WriteChecksumFile( g_fpChecksumFile, aLibraries ); |
| WriteReportFile( &Params ); |
| |
| FILE *fpPreview = _open_reportfile( _T(".prv"), _T("w+b") ); |
| |
| if ( fpPreview ) |
| { |
| FILE *fp = fopen( g_szReportFileNameA, "rb" ); |
| if ( fp ) |
| { |
| fcopy( fp, fpPreview ); |
| fclose( fp ); |
| } |
| fclose( fpPreview ); |
| } |
| } |
| |
| if ( g_bSendReport ) |
| { |
| InitCommonControls(); |
| |
| // Actually this should never be true anymore |
| if ( !g_bNoUserInterface && InitRichEdit() ) |
| { |
| |
| INT_PTR result = DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG_FRAME), NULL, DialogProc, (LPARAM)&Params ); |
| |
| if ( result > 0 ) |
| { |
| exitcode = 0; |
| } |
| DeinitRichEdit(); |
| } |
| else |
| { |
| WriteCommentFile( Params.sComment.c_str() ); |
| WriteReportFile( &Params ); |
| if ( SendCrashReport( NULL, Params ) ) |
| exitcode = 0; |
| } |
| |
| |
| if ( g_szReportFileNameA[0] ) |
| DeleteFileA( g_szReportFileNameA ); |
| |
| if ( g_szCommentFileNameA[0] ) |
| DeleteFileA( g_szCommentFileNameA ); |
| } |
| else |
| { |
| if ( g_szReportFileNameA[0] ) |
| DeleteFileA( g_szReportFileNameA ); |
| exitcode = 0; |
| } |
| |
| if ( g_szDumpFileNameA[0] && g_bSendReport ) |
| DeleteFileA( g_szDumpFileNameA ); |
| |
| if ( g_fpStackFile ) |
| fclose( g_fpStackFile ); |
| |
| if ( g_fpChecksumFile ) |
| fclose( g_fpChecksumFile ); |
| } |
| } |
| |
| |
| return exitcode; |
| } |
| |