diff options
author | Hennes Rohling <hro@openoffice.org> | 2003-06-06 10:22:06 +0000 |
---|---|---|
committer | Hennes Rohling <hro@openoffice.org> | 2003-06-06 10:22:06 +0000 |
commit | babbec197979c6ba6b7f48457a881cf96c778008 (patch) | |
tree | 64ddfdb205230dfb54bdcdf9b736e298c29c46b8 | |
parent | 451b61ea9ee8595fb03ddbdc19d9716400c1e5ac (diff) |
#i15275# Move crashrep sources to OOo cvs module
-rwxr-xr-x | crashrep/prj/build.lst | 6 | ||||
-rwxr-xr-x | crashrep/prj/d.lst | 44 | ||||
-rwxr-xr-x | crashrep/source/unx/interface.cxx | 659 | ||||
-rwxr-xr-x | crashrep/source/unx/interface.hxx | 158 | ||||
-rwxr-xr-x | crashrep/source/unx/main.cxx | 1103 | ||||
-rwxr-xr-x | crashrep/source/unx/makefile.mk | 101 | ||||
-rwxr-xr-x | crashrep/source/unx/res.cxx | 108 | ||||
-rwxr-xr-x | crashrep/source/unx/res/makefile.mk | 22 | ||||
-rwxr-xr-x | crashrep/source/unx/res/unxcrashres.cxx | 80 | ||||
-rwxr-xr-x | crashrep/source/win32/base64.cpp | 56 | ||||
-rwxr-xr-x | crashrep/source/win32/base64.h | 19 | ||||
-rwxr-xr-x | crashrep/source/win32/ctrylnglist.txt | 29 | ||||
-rwxr-xr-x | crashrep/source/win32/makefile.mk | 117 | ||||
-rwxr-xr-x | crashrep/source/win32/rcfooter.txt | 1 | ||||
-rwxr-xr-x | crashrep/source/win32/rcheader.txt | 4 | ||||
-rwxr-xr-x | crashrep/source/win32/rctemplate.txt | 168 | ||||
-rwxr-xr-x | crashrep/source/win32/resource.h | 94 | ||||
-rwxr-xr-x | crashrep/source/win32/soreport.cpp | 2272 |
18 files changed, 5041 insertions, 0 deletions
diff --git a/crashrep/prj/build.lst b/crashrep/prj/build.lst new file mode 100755 index 000000000..2ef317cc0 --- /dev/null +++ b/crashrep/prj/build.lst @@ -0,0 +1,6 @@ +cr crashrep : sal sysui gtk tools NULL +cr crashrep usr1 - all cr_mkout NULL +cr crashrep\source\unx\res nmake - u cr_sures NULL +cr crashrep\source\unx nmake - u cr_sunx cr_sures.u NULL +cr crashrep nmake - u cr_supstack NULL +cr crashrep\source\win32 nmake - n cr_swin32 NULL diff --git a/crashrep/prj/d.lst b/crashrep/prj/d.lst new file mode 100755 index 000000000..75937ab33 --- /dev/null +++ b/crashrep/prj/d.lst @@ -0,0 +1,44 @@ +mkdir: %_DEST%\bin%_EXT%\01 +mkdir: %_DEST%\bin%_EXT%\03 +mkdir: %_DEST%\bin%_EXT%\07 +mkdir: %_DEST%\bin%_EXT%\30 +mkdir: %_DEST%\bin%_EXT%\31 +mkdir: %_DEST%\bin%_EXT%\33 +mkdir: %_DEST%\bin%_EXT%\34 +mkdir: %_DEST%\bin%_EXT%\39 +mkdir: %_DEST%\bin%_EXT%\45 +mkdir: %_DEST%\bin%_EXT%\46 +mkdir: %_DEST%\bin%_EXT%\48 +mkdir: %_DEST%\bin%_EXT%\49 +mkdir: %_DEST%\bin%_EXT%\66 +mkdir: %_DEST%\bin%_EXT%\81 +mkdir: %_DEST%\bin%_EXT%\82 +mkdir: %_DEST%\bin%_EXT%\86 +mkdir: %_DEST%\bin%_EXT%\88 +mkdir: %_DEST%\bin%_EXT%\90 +mkdir: %_DEST%\bin%_EXT%\96 +..\%__SRC%\bin\01\soreport.exe %_DEST%\bin%_EXT%\crashrep.exe +..\%__SRC%\bin\soreport.exe.manifest %_DEST%\bin%_EXT%\crashrep.exe.manifest +%_DEST%\bin%_EXT%\guistdio.com %_DEST%\bin%_EXT%\crashrep.com +..\%__SRC%\bin\crash_report* %_DEST%\bin%_EXT%\crash_report* +..\%__SRC%\bin\pstack %_DEST%\bin%_EXT%\pstack.bin +..\%__SRC%\bin\crash_dump.res.01 %_DEST%\bin%_EXT%\01\crash_dump.res +..\%__SRC%\bin\crash_dump.res.03 %_DEST%\bin%_EXT%\03\crash_dump.res +..\%__SRC%\bin\crash_dump.res.07 %_DEST%\bin%_EXT%\07\crash_dump.res +..\%__SRC%\bin\crash_dump.res.30 %_DEST%\bin%_EXT%\30\crash_dump.res +..\%__SRC%\bin\crash_dump.res.31 %_DEST%\bin%_EXT%\31\crash_dump.res +..\%__SRC%\bin\crash_dump.res.33 %_DEST%\bin%_EXT%\33\crash_dump.res +..\%__SRC%\bin\crash_dump.res.34 %_DEST%\bin%_EXT%\34\crash_dump.res +..\%__SRC%\bin\crash_dump.res.39 %_DEST%\bin%_EXT%\39\crash_dump.res +..\%__SRC%\bin\crash_dump.res.45 %_DEST%\bin%_EXT%\45\crash_dump.res +..\%__SRC%\bin\crash_dump.res.46 %_DEST%\bin%_EXT%\46\crash_dump.res +..\%__SRC%\bin\crash_dump.res.48 %_DEST%\bin%_EXT%\48\crash_dump.res +..\%__SRC%\bin\crash_dump.res.49 %_DEST%\bin%_EXT%\49\crash_dump.res +..\%__SRC%\bin\crash_dump.res.66 %_DEST%\bin%_EXT%\66\crash_dump.res +..\%__SRC%\bin\crash_dump.res.81 %_DEST%\bin%_EXT%\81\crash_dump.res +..\%__SRC%\bin\crash_dump.res.82 %_DEST%\bin%_EXT%\82\crash_dump.res +..\%__SRC%\bin\crash_dump.res.86 %_DEST%\bin%_EXT%\86\crash_dump.res +..\%__SRC%\bin\crash_dump.res.88 %_DEST%\bin%_EXT%\88\crash_dump.res +..\%__SRC%\bin\crash_dump.res.90 %_DEST%\bin%_EXT%\90\crash_dump.res +..\%__SRC%\bin\crash_dump.res.96 %_DEST%\bin%_EXT%\96\crash_dump.res +%_DEST%\bin%_EXT%\guistdio.com %_DEST%\bin%_EXT%\crashrep.com diff --git a/crashrep/source/unx/interface.cxx b/crashrep/source/unx/interface.cxx new file mode 100755 index 000000000..0249864cc --- /dev/null +++ b/crashrep/source/unx/interface.cxx @@ -0,0 +1,659 @@ +#include <interface.hxx> +#include <iostream.h> + +using namespace std; + +/* + * WizardPage + */ +WizardPage::~WizardPage() +{ +} + +/* + * WizardDialog + */ + +WizardDialog::WizardDialog() +{ + m_pStatusDialog = NULL; + m_pTopLevel = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW(m_pTopLevel), StringResource::get( "%WELCOME_CAPTION%" ) ); + + m_pVBox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( m_pVBox ); + gtk_container_add( GTK_CONTAINER(m_pTopLevel), m_pVBox ); + + m_pViewPort = gtk_viewport_new( NULL, NULL ); + gtk_widget_show( m_pViewPort ); + + // set wizard title style + gtk_widget_ensure_style( m_pViewPort ); + GtkStyle* pStyle = gtk_style_copy( gtk_widget_get_style( m_pViewPort ) ); + for( int i = 0; i < 5; i++ ) + { + pStyle->bg[i] = pStyle->white; + pStyle->text[i] = pStyle->black; + pStyle->bg_gc[i] = pStyle->white_gc; + pStyle->text_gc[i] = pStyle->black_gc; + } + gint nFontSize = pango_font_description_get_size( pStyle->font_desc ); + nFontSize = nFontSize * 3 / 2; + pango_font_description_set_size( pStyle->font_desc, nFontSize ); + gtk_widget_set_style( m_pViewPort, pStyle ); + gtk_viewport_set_shadow_type( GTK_VIEWPORT(m_pViewPort), GTK_SHADOW_NONE ); + gtk_box_pack_start( GTK_BOX(m_pVBox), m_pViewPort, FALSE, FALSE, 0 ); + + m_pWizardTitle = gtk_label_new( "Wizard" ); // to be replaced by resp. page titles + gtk_widget_show( m_pWizardTitle ); + gtk_label_set_justify( GTK_LABEL(m_pWizardTitle), GTK_JUSTIFY_LEFT ); + gtk_misc_set_alignment( GTK_MISC(m_pWizardTitle), 0, 1 ); + gtk_misc_set_padding( GTK_MISC(m_pWizardTitle), 10, 10 ); + gtk_widget_set_style( m_pWizardTitle, pStyle ); + gtk_container_add( GTK_CONTAINER(m_pViewPort), m_pWizardTitle ); + + // prepare the area for the single pages + m_pPageArea = gtk_vbox_new( FALSE, 1); + gtk_widget_show( m_pPageArea ); + gtk_box_pack_start( GTK_BOX(m_pVBox), m_pPageArea, TRUE, TRUE, 0 ); + + m_pSeparator = gtk_hseparator_new(); + gtk_widget_show( m_pSeparator ); + gtk_box_pack_start( GTK_BOX(m_pVBox), m_pSeparator, FALSE, FALSE, 0 ); + + m_pButtonBox = gtk_hbutton_box_new(); + gtk_widget_show( m_pButtonBox ); + gtk_box_pack_start( GTK_BOX(m_pVBox), m_pButtonBox, FALSE, FALSE, 0 ); + gtk_button_box_set_layout( GTK_BUTTON_BOX(m_pButtonBox), GTK_BUTTONBOX_END ); + gtk_button_box_set_spacing( GTK_BUTTON_BOX(m_pButtonBox), 0 ); + + m_pBackButton = gtk_button_new_with_mnemonic( StringResource::get( "%BACK_BUTTON%" ) ); + gtk_widget_show( m_pBackButton ); + gtk_container_add( GTK_CONTAINER(m_pButtonBox), m_pBackButton ); + gtk_container_set_border_width( GTK_CONTAINER(m_pBackButton), 5 ); + GTK_WIDGET_SET_FLAGS( m_pBackButton, GTK_CAN_DEFAULT ); + + m_pNextButton = gtk_button_new_with_mnemonic( StringResource::get( "%NEXT_BUTTON%" ) ); + gtk_widget_show( m_pNextButton ); + gtk_container_add( GTK_CONTAINER(m_pButtonBox), m_pNextButton ); + gtk_container_set_border_width( GTK_CONTAINER(m_pNextButton), 5 ); + GTK_WIDGET_SET_FLAGS( m_pNextButton, GTK_CAN_DEFAULT ); + + m_pSendButton = gtk_button_new_with_mnemonic( StringResource::get( "%SEND_BUTTON%" ) ); + gtk_widget_show( m_pSendButton ); + gtk_container_add( GTK_CONTAINER(m_pButtonBox), m_pSendButton ); + gtk_container_set_border_width( GTK_CONTAINER(m_pSendButton), 5 ); + GTK_WIDGET_SET_FLAGS( m_pSendButton, GTK_CAN_DEFAULT ); + + m_pCancelButton = gtk_button_new_with_mnemonic( StringResource::get( "%DONOT_SEND_BUTTON%" ) ); + gtk_widget_show( m_pCancelButton ); + gtk_container_add( GTK_CONTAINER(m_pButtonBox), m_pCancelButton ); + gtk_container_set_border_width( GTK_CONTAINER(m_pCancelButton), 5 ); + GTK_WIDGET_SET_FLAGS( m_pCancelButton, GTK_CAN_DEFAULT ); + + gtk_signal_connect( GTK_OBJECT(m_pTopLevel), "delete-event", G_CALLBACK(gtk_main_quit), NULL ); + gtk_signal_connect( GTK_OBJECT(m_pCancelButton), "clicked", G_CALLBACK(gtk_main_quit), NULL ); + gtk_signal_connect( GTK_OBJECT(m_pNextButton), "clicked", G_CALLBACK(button_clicked), this ); + gtk_signal_connect( GTK_OBJECT(m_pBackButton), "clicked", G_CALLBACK(button_clicked), this ); + gtk_signal_connect( GTK_OBJECT(m_pSendButton), "clicked", G_CALLBACK(button_clicked), this ); + gtk_widget_set_sensitive( m_pSendButton, FALSE ); + + m_nCurrentPage = -1; +} + +WizardDialog::~WizardDialog() +{ + int nPages = m_aPages.size(); + while( nPages-- ) + delete m_aPages[nPages]; +} + +void WizardDialog::show_messagebox( const std::string& rMessage ) +{ + GtkWidget* messagebox = NULL; + GtkMessageType eType = GTK_MESSAGE_ERROR; + + messagebox = gtk_message_dialog_new( NULL, + (GtkDialogFlags)0, + eType, + GTK_BUTTONS_OK, + rMessage.c_str(), + NULL + ); + + gtk_dialog_run( GTK_DIALOG(messagebox) ); + gtk_widget_destroy( GTK_WIDGET(messagebox) ); +} + + + +// bInProgress: true=sending, false=finished +gint WizardDialog::show_sendingstatus( bool bInProgress ) +{ + m_pStatusDialog = gtk_dialog_new_with_buttons( StringResource::get( "%SENDING_REPORT_HEADER%" ), + getTopLevel(), + GTK_DIALOG_MODAL, + bInProgress ? GTK_STOCK_CANCEL : GTK_STOCK_OK, + bInProgress ? GTK_RESPONSE_REJECT : GTK_RESPONSE_OK, + NULL ); + + gtk_window_set_default_size( GTK_WINDOW(m_pStatusDialog), 350, 130 ); + + GtkWidget *pLabel = gtk_label_new( bInProgress ? StringResource::get( "%SENDING_REPORT_STATUS%" ) : + StringResource::get( "%SENDING_REPORT_STATUS_FINISHED%" ) ); + gtk_widget_show( pLabel ); + gtk_label_set_justify( GTK_LABEL(pLabel), GTK_JUSTIFY_CENTER); + gtk_misc_set_alignment( GTK_MISC(pLabel), 0, 0 ); + + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(m_pStatusDialog)->vbox), pLabel ); + + gint ret = gtk_dialog_run( GTK_DIALOG(m_pStatusDialog) ); + gtk_widget_destroy( m_pStatusDialog ); + m_pStatusDialog = NULL; + + return ret; +} + +void WizardDialog::hide_sendingstatus() +{ + if( m_pStatusDialog ) + { + gtk_dialog_response( GTK_DIALOG(m_pStatusDialog), GTK_RESPONSE_OK ); + } +} + + +gint WizardDialog::button_clicked( GtkWidget* pButton, WizardDialog* pThis ) +{ + if( pButton == pThis->m_pNextButton ) + pThis->nextPage(); + else if( pButton == pThis->m_pBackButton ) + pThis->lastPage(); + else if( pButton == pThis->m_pSendButton ) + { + if( pThis->m_nCurrentPage != -1 ) + pThis->m_aPages[pThis->m_nCurrentPage]->update(); + + if( send_crash_report( *pThis, pThis->getSettings() ) ) + gtk_main_quit(); + } + + return 0; +} + +void WizardDialog::insertPage( WizardPage* pPage ) +{ + m_aPages.push_back( pPage ); + if( m_nCurrentPage == -1 ) + { + m_nCurrentPage = 0; + gtk_label_set_text( GTK_LABEL(m_pWizardTitle), pPage->getTitle() ); + gtk_box_pack_start( GTK_BOX(m_pPageArea), pPage->getContents(), TRUE, TRUE, 0 ); + gtk_widget_set_sensitive( m_pNextButton, FALSE ); + gtk_widget_set_sensitive( m_pBackButton, FALSE ); + } + else + { + gtk_widget_set_sensitive( m_pNextButton, TRUE ); + } +} + +void WizardDialog::nextPage() +{ + if( m_aPages.empty() || m_nCurrentPage >= (int)m_aPages.size()-1 ) + return; + + m_aPages[m_nCurrentPage]->update(); + + gtk_container_remove( GTK_CONTAINER(m_pPageArea), m_aPages[m_nCurrentPage]->getContents() ); + m_nCurrentPage++; + gtk_label_set_text( GTK_LABEL(m_pWizardTitle), m_aPages[m_nCurrentPage]->getTitle() ); + gtk_box_pack_start( GTK_BOX(m_pPageArea), m_aPages[m_nCurrentPage]->getContents(), TRUE, TRUE, 0 ); + + if( m_nCurrentPage == (int)m_aPages.size()-1 ) + { + gtk_widget_set_sensitive( m_pNextButton, FALSE ); + gtk_widget_set_sensitive( m_pSendButton, TRUE ); + } + if( m_aPages.size() > 1 ) + gtk_widget_set_sensitive( m_pBackButton, TRUE ); +} + +void WizardDialog::lastPage() +{ + if( m_aPages.empty() || m_nCurrentPage <= 0 ) + return; + + m_aPages[m_nCurrentPage]->update(); + + gtk_container_remove( GTK_CONTAINER(m_pPageArea), m_aPages[m_nCurrentPage]->getContents() ); + m_nCurrentPage--; + gtk_label_set_text( GTK_LABEL(m_pWizardTitle), m_aPages[m_nCurrentPage]->getTitle() ); + gtk_box_pack_start( GTK_BOX(m_pPageArea), m_aPages[m_nCurrentPage]->getContents(), TRUE, TRUE, 0 ); + + if( m_nCurrentPage == 0 ) + gtk_widget_set_sensitive( m_pBackButton, FALSE ); + if( m_aPages.size() > 1 ) + gtk_widget_set_sensitive( m_pNextButton, TRUE ); +} + +void WizardDialog::show( bool bShow ) +{ + if( bShow ) + gtk_widget_show( m_pTopLevel ); + else + gtk_widget_hide( m_pTopLevel ); +} + +/* + * MainPage + */ + +MainPage::MainPage( WizardDialog* pParent ) : WizardPage( pParent ) +{ + hash_map< string, string >& rSettings = m_pDialog->getSettings(); + m_aWizardTitle = StringResource::get( "%REPORT_HEADER%" ); + + m_pPageContents = gtk_vbox_new( FALSE, 0 ); + gtk_widget_show( m_pPageContents ); + + m_pInfo = gtk_label_new( StringResource::get( "%REPORT_BODY%" ) ); + gtk_widget_show( m_pInfo ); + gtk_label_set_line_wrap( GTK_LABEL(m_pInfo), TRUE ); + gtk_label_set_justify( GTK_LABEL(m_pInfo), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pInfo), 0, 1 ); + gtk_misc_set_padding( GTK_MISC(m_pInfo ), 5, 5); + gtk_box_pack_start( GTK_BOX(m_pPageContents), m_pInfo, FALSE, FALSE, 0 ); + + m_pHBox = gtk_hbox_new( FALSE, 0 ); + gtk_widget_show( m_pHBox ); + gtk_box_pack_start( GTK_BOX(m_pPageContents), m_pHBox, TRUE, TRUE, 0 ); + + m_pLeftColumn = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( m_pLeftColumn ); + gtk_container_set_border_width( GTK_CONTAINER(m_pLeftColumn), 5 ); + gtk_box_pack_start( GTK_BOX(m_pHBox), m_pLeftColumn, TRUE, TRUE, 0 ); + + m_pRightColumn = gtk_vbutton_box_new(); + gtk_widget_show( m_pRightColumn ); + gtk_button_box_set_layout( GTK_BUTTON_BOX(m_pRightColumn), GTK_BUTTONBOX_END ); + gtk_box_pack_start( GTK_BOX(m_pHBox), m_pRightColumn, FALSE, FALSE, 0 ); + + m_pEditLabel = gtk_label_new_with_mnemonic( StringResource::get( "%ENTER_TITLE%" ) ); + gtk_widget_show( m_pEditLabel ); + gtk_label_set_justify( GTK_LABEL(m_pEditLabel), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pEditLabel), 0, 1 ); + gtk_box_pack_start( GTK_BOX(m_pLeftColumn), m_pEditLabel, FALSE, FALSE, 0 ); + + m_pEdit = gtk_entry_new(); + gtk_widget_show( m_pEdit ); + gtk_box_pack_start( GTK_BOX(m_pLeftColumn), m_pEdit, FALSE, FALSE, 0 ); + + gtk_label_set_mnemonic_widget( GTK_LABEL(m_pEditLabel), m_pEdit ); + + m_pEntryVBox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( m_pEntryVBox ); + gtk_box_pack_start( GTK_BOX(m_pLeftColumn), m_pEntryVBox, TRUE, TRUE, 0 ); + + m_pEntryLabel = gtk_label_new_with_mnemonic( StringResource::get( "%ENTER_DESCRIPTION%" ) ); + gtk_widget_show( m_pEntryLabel ); + gtk_label_set_justify( GTK_LABEL(m_pEntryLabel), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pEntryLabel), 0, 1 ); + gtk_box_pack_start( GTK_BOX(m_pEntryVBox), m_pEntryLabel, FALSE, FALSE, 0 ); + + m_pScrolledEntry = gtk_scrolled_window_new( NULL, NULL ); + gtk_widget_show( m_pScrolledEntry ); + gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(m_pScrolledEntry), GTK_SHADOW_IN ); + gtk_box_pack_start( GTK_BOX(m_pEntryVBox), m_pScrolledEntry, TRUE, TRUE, 0 ); + + m_pEntry = gtk_text_view_new(); + gtk_widget_show( m_pEntry ); + gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(m_pEntry), GTK_WRAP_WORD ); + gtk_container_add( GTK_CONTAINER(m_pScrolledEntry), m_pEntry ); + + gtk_label_set_mnemonic_widget( GTK_LABEL(m_pEntryLabel), m_pEntry ); + + m_pDetails = gtk_button_new_with_mnemonic( StringResource::get( "%SHOW_REPORT_BUTTON%" ) ); + gtk_widget_show(m_pDetails); + gtk_container_set_border_width( GTK_CONTAINER(m_pDetails), 5 ); + gtk_container_add( GTK_CONTAINER(m_pRightColumn), m_pDetails ); + + m_pOptions = gtk_button_new_with_mnemonic( StringResource::get( "%OPTIONS_BUTTON%" ) ); + gtk_widget_show(m_pOptions); + gtk_container_set_border_width( GTK_CONTAINER(m_pOptions), 5 ); + gtk_container_add( GTK_CONTAINER(m_pRightColumn), m_pOptions ); + + // check env var for save button + const char *szUserType = getenv( "STAROFFICE_USERTYPE" ); + if( szUserType && *szUserType ) + { + m_pSave = gtk_button_new_with_mnemonic( StringResource::get( "%SAVE_REPORT_BUTTON%" ) ); + gtk_widget_show(m_pSave); + gtk_container_set_border_width( GTK_CONTAINER(m_pSave), 5 ); + gtk_container_add( GTK_CONTAINER(m_pRightColumn), m_pSave ); + } + else + m_pSave = NULL; + + + m_pCheck = gtk_check_button_new_with_mnemonic( StringResource::get( "%ALLOW_CONTACT%" ) ); + gtk_widget_show( m_pCheck ); + gtk_container_set_border_width( GTK_CONTAINER(m_pCheck), 5 ); + //gtk_box_pack_start( GTK_BOX(m_pPageContents), m_pCheck, FALSE, FALSE, 5 ); + gtk_box_pack_start( GTK_BOX(m_pLeftColumn), m_pCheck, FALSE, FALSE, 5 ); + + hash_map<string, string>::iterator aIter; + aIter = rSettings.find( "CONTACT" ); + if( aIter != rSettings.end() ) + { + const char *str = aIter->second.c_str(); + if( str && !strcasecmp(str, "true") ) + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(m_pCheck), TRUE ); + } + + m_pAddressLabel = gtk_label_new_with_mnemonic( StringResource::get( "%ENTER_EMAIL%" ) ); + gtk_widget_show( m_pAddressLabel ); + gtk_label_set_justify( GTK_LABEL(m_pAddressLabel), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pAddressLabel), 0, 1 ); + gtk_box_pack_start( GTK_BOX(m_pLeftColumn), m_pAddressLabel, FALSE, FALSE, 5 ); + + m_pAddress = gtk_entry_new(); + gtk_widget_show( m_pAddress ); + gtk_box_pack_start( GTK_BOX(m_pLeftColumn), m_pAddress, FALSE, FALSE, 5 ); + + aIter = rSettings.find( "EMAIL" ); + if( aIter != rSettings.end() ) + gtk_entry_set_text( GTK_ENTRY(m_pAddress), aIter->second.c_str() ); + + gtk_signal_connect( GTK_OBJECT(m_pDetails), "clicked", G_CALLBACK(button_clicked), this ); + gtk_signal_connect( GTK_OBJECT(m_pOptions), "clicked", G_CALLBACK(button_clicked), this ); + if(m_pSave) // optional + gtk_signal_connect( GTK_OBJECT(m_pSave), "clicked", G_CALLBACK(button_clicked), this ); + + gtk_signal_connect( GTK_OBJECT(m_pCheck), "toggled", G_CALLBACK(button_toggled), this ); + button_toggled( m_pCheck, this ); + + g_object_ref( G_OBJECT(m_pPageContents) ); +} + +MainPage::~MainPage() +{ + g_object_unref( G_OBJECT(m_pPageContents) ); +} + +void MainPage::update() +{ + hash_map< string, string >& rSettings = m_pDialog->getSettings(); + + GtkTextIter start, end; + GtkTextBuffer* pTextBuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_pEntry) ); + gtk_text_buffer_get_bounds( pTextBuffer, &start, &end ); + rSettings[ "DESCRIPTION" ] = gtk_text_buffer_get_text( pTextBuffer, &start, &end, 1 ); + rSettings[ "TITLE" ] = gtk_entry_get_text( GTK_ENTRY(m_pEdit) ); + rSettings[ "CONTACT" ] = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(m_pCheck) ) ? "true" : "false"; + rSettings[ "EMAIL" ] = gtk_entry_get_text( GTK_ENTRY(m_pAddress) ); +} + +gint MainPage::button_toggled( GtkWidget* pButton, MainPage* pThis ) +{ + if ( GTK_TOGGLE_BUTTON (pThis->m_pCheck)->active ) + { + gtk_widget_set_sensitive( pThis->m_pAddressLabel, TRUE); + gtk_widget_set_sensitive( pThis->m_pAddress, TRUE); + } + else + { + gtk_widget_set_sensitive( pThis->m_pAddressLabel, FALSE); + gtk_widget_set_sensitive( pThis->m_pAddress, FALSE); + } + return 0; +} + +gint MainPage::button_clicked( GtkWidget* pButton, MainPage* pThis ) +{ + if( pButton == pThis->m_pSave ) + { + GtkWidget* pFile = gtk_file_selection_new( StringResource::get( "%SAVE_REPORT_TITLE%" ) ); + gint nRet = gtk_dialog_run( GTK_DIALOG(pFile) ); + if( nRet == GTK_RESPONSE_OK ) + { + string aFile = gtk_file_selection_get_filename( GTK_FILE_SELECTION(pFile) ); + pThis->update(); + if( save_crash_report( aFile, pThis->m_pDialog->getSettings() ) ) + { + // gtk_main_quit(); + } + } + gtk_widget_destroy( pFile ); + } + else if( pButton == pThis->m_pDetails ) + { + pThis->update(); + + GtkWidget* pDialog = gtk_dialog_new_with_buttons( StringResource::get( "%REPORT_CAPTION%" ), + pThis->m_pDialog->getTopLevel(), + GTK_DIALOG_MODAL, + GTK_STOCK_OK, + GTK_RESPONSE_OK, + NULL ); + + gtk_window_set_default_size( GTK_WINDOW(pDialog), 500, 300 ); + GtkWidget* pScroll = gtk_scrolled_window_new( NULL, NULL ); + gtk_widget_show( pScroll ); + gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(pScroll), GTK_SHADOW_IN ); + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(pDialog)->vbox), pScroll ); + + string aText = crash_get_details( pThis->m_pDialog->getSettings() ); + GtkWidget* pView = gtk_text_view_new(); + gtk_widget_show( pView ); + gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW(pView), GTK_WRAP_WORD ); + gtk_text_view_set_editable( GTK_TEXT_VIEW(pView), FALSE ); + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(pView) ); + gtk_text_buffer_set_text( pBuffer, aText.data(), aText.size() ); + gtk_container_add( GTK_CONTAINER(pScroll), pView ); + + gtk_dialog_run( GTK_DIALOG(pDialog) ); + gtk_widget_destroy( pDialog ); + } + else if( pButton == pThis->m_pOptions ) + { + OptionsDialog aOptions( pThis->m_pDialog->getTopLevel(), pThis->m_pDialog->getSettings() ); + //pThis->m_pDialog->show_sendingstatus( true ); + //pThis->m_pDialog->show_sendingstatus( false ); + //sleep(5); + //pThis->m_pDialog->hide_sendingstatus(); + } + + return 0; +} + +/* + * OptionsDialog (Proxy-Settings) + */ + +OptionsDialog::OptionsDialog( GtkWindow *pParent ,hash_map< string, string >& rSettings ) +{ + m_pDialog = gtk_dialog_new_with_buttons( StringResource::get( "%OPTIONS_TITLE%" ), + pParent, + GTK_DIALOG_MODAL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + NULL ); + + gtk_window_set_default_size( GTK_WINDOW(m_pDialog), 500, 300 ); + + m_pPage = gtk_vbox_new( FALSE, 0 ); + m_pLeftColumn = gtk_vbox_new( FALSE, 5 ); + + gtk_widget_show( m_pPage ); + gtk_widget_show( m_pLeftColumn ); + + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(m_pDialog)->vbox), m_pPage ); + + gtk_container_set_border_width( GTK_CONTAINER(m_pLeftColumn), 5 ); + gtk_box_pack_start( GTK_BOX(m_pPage), m_pLeftColumn, FALSE, FALSE, 5 ); + + // frame for proxy settings + m_pFrame = gtk_frame_new(StringResource::get( "%PROXY_SETTINGS_HEADER%" )); + gtk_frame_set_shadow_type( GTK_FRAME(m_pFrame), GTK_SHADOW_ETCHED_IN ); + gtk_widget_show(m_pFrame); + gtk_box_pack_start(GTK_BOX (m_pLeftColumn), m_pFrame, TRUE, TRUE, 0); + + m_pVBox = gtk_vbox_new( FALSE, 0 ); + gtk_widget_show( m_pVBox ); + gtk_container_add( GTK_CONTAINER( m_pFrame ), m_pVBox ); + + // the radio buttons + m_pDirect = gtk_radio_button_new_with_mnemonic( NULL, + StringResource::get( "%PROXY_SETTINGS_DIRECT%" ) ); + gtk_widget_show(m_pDirect); + gtk_box_pack_start(GTK_BOX (m_pVBox), m_pDirect, FALSE, FALSE, 0); + + m_pManual = gtk_radio_button_new_with_mnemonic( gtk_radio_button_group( GTK_RADIO_BUTTON(m_pDirect) ), + StringResource::get( "%PROXY_SETTINGS_MANUAL%" ) ); + gtk_widget_show(m_pManual); + gtk_box_pack_start(GTK_BOX (m_pVBox), m_pManual, FALSE, FALSE, 0); + + hash_map<string, string>::iterator aIter; + const char *str = NULL; + aIter = rSettings.find( "USEPROXY" ); + if( aIter != rSettings.end() ) + str = aIter->second.c_str(); + if( str && !strcasecmp(str, "true") ) + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(m_pManual), TRUE ); + else + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(m_pDirect), TRUE ); + + // the server and port edit controls + m_pHBox = gtk_hbox_new( FALSE, 0 ); + gtk_widget_show( m_pHBox ); + gtk_box_pack_start(GTK_BOX (m_pVBox), m_pHBox, FALSE, FALSE, 10); + + m_pVBoxServer = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( m_pVBoxServer ); + gtk_box_pack_start(GTK_BOX (m_pHBox), m_pVBoxServer, TRUE, TRUE, 10); + + m_pVBoxPort = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( m_pVBoxPort ); + gtk_box_pack_start(GTK_BOX (m_pHBox), m_pVBoxPort, FALSE, FALSE, 10); + + m_pServerLabel = gtk_label_new_with_mnemonic( StringResource::get( "%PROXY_SETTINGS_ADDRESS%" ) ); + gtk_widget_show( m_pServerLabel ); + gtk_label_set_justify( GTK_LABEL(m_pServerLabel), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pServerLabel), 0, 1 ); + gtk_box_pack_start( GTK_BOX(m_pVBoxServer), m_pServerLabel, FALSE, FALSE, 0 ); + + m_pServer = gtk_entry_new(); + gtk_widget_show( m_pServer ); + gtk_box_pack_start( GTK_BOX(m_pVBoxServer), m_pServer, FALSE, FALSE, 0 ); + gtk_label_set_mnemonic_widget( GTK_LABEL(m_pServerLabel), m_pServer ); + aIter = rSettings.find( "SERVER" ); + if( aIter != rSettings.end() ) + gtk_entry_set_text( GTK_ENTRY(m_pServer), aIter->second.c_str() ); + + m_pPortLabel = gtk_label_new_with_mnemonic( StringResource::get( "%PROXY_SETTINGS_PORT%" ) ); + gtk_widget_show( m_pPortLabel ); + gtk_label_set_justify( GTK_LABEL(m_pPortLabel), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pPortLabel), 0, 1 ); + gtk_box_pack_start( GTK_BOX(m_pVBoxPort), m_pPortLabel, FALSE, FALSE, 0 ); + + m_pPort = gtk_entry_new(); + gtk_widget_show( m_pPort ); + gtk_box_pack_start( GTK_BOX(m_pVBoxPort), m_pPort, FALSE, FALSE, 0 ); + gtk_label_set_mnemonic_widget( GTK_LABEL(m_pPortLabel), m_pPort ); + aIter = rSettings.find( "PORT" ); + if( aIter != rSettings.end() ) + gtk_entry_set_text( GTK_ENTRY(m_pPort), aIter->second.c_str() ); + + // help text + m_pNote = gtk_label_new( StringResource::get( "%PROXY_SETTINGS_DESCRIPTION%" ) ); + gtk_widget_show( m_pNote ); + gtk_label_set_justify( GTK_LABEL(m_pNote), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pNote), 0, 1 ); + gtk_box_pack_start(GTK_BOX (m_pLeftColumn), m_pNote, FALSE, FALSE, 5); + gtk_label_set_line_wrap (GTK_LABEL (m_pNote), TRUE); + + + gtk_signal_connect( GTK_OBJECT(m_pDirect), "toggled", G_CALLBACK(button_toggled), this ); + gtk_signal_connect( GTK_OBJECT(m_pManual), "toggled", G_CALLBACK(button_toggled), this ); + + button_toggled( m_pDirect, this ); + + if( gtk_dialog_run( GTK_DIALOG(m_pDialog) ) == GTK_RESPONSE_OK ) + { + rSettings[ "SERVER" ] = getServer(); + rSettings[ "PORT" ] = getPort(); + rSettings[ "USEPROXY" ] = getUseProxy(); + } + g_object_ref( G_OBJECT(m_pDialog) ); +} + +OptionsDialog::~OptionsDialog() +{ + gtk_widget_destroy( m_pDialog ); + g_object_unref( G_OBJECT(m_pDialog) ); +} + +gint OptionsDialog::button_toggled( GtkWidget* pButton, OptionsDialog* pThis ) +{ + if ( GTK_TOGGLE_BUTTON (pThis->m_pManual)->active ) + { + gtk_widget_set_sensitive( pThis->m_pServerLabel, TRUE); + gtk_widget_set_sensitive( pThis->m_pServer, TRUE); + gtk_widget_set_sensitive( pThis->m_pPortLabel, TRUE); + gtk_widget_set_sensitive( pThis->m_pPort, TRUE); + } + else + { + gtk_widget_set_sensitive( pThis->m_pServerLabel, FALSE); + gtk_widget_set_sensitive( pThis->m_pServer, FALSE); + gtk_widget_set_sensitive( pThis->m_pPortLabel, FALSE); + gtk_widget_set_sensitive( pThis->m_pPort, FALSE); + } + + return 0; +} + +string OptionsDialog::getUseProxy() +{ + return gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(m_pDirect) ) ? "false" : "true"; +} +string OptionsDialog::getServer() +{ + return gtk_entry_get_text( GTK_ENTRY(m_pServer) ); +} +string OptionsDialog::getPort() +{ + return gtk_entry_get_text( GTK_ENTRY(m_pPort) ); +} + +/* + * WelcomePage + */ +WelcomePage::WelcomePage( WizardDialog* pParent ) : WizardPage( pParent ) +{ + m_aWizardTitle = StringResource::get( "%WELCOME_HEADER%" ); + + string aBody = StringResource::get( "%WELCOME_BODY1%" ); + aBody += StringResource::get( "%WELCOME_BODY2%" ); + aBody += StringResource::get( "%WELCOME_BODY3%" ); + aBody += "\n\n"; + aBody += StringResource::get( "%PRIVACY_URL%" ); + m_pPageContents = gtk_label_new( aBody.c_str() ); + gtk_widget_show( m_pPageContents ); + gtk_label_set_line_wrap( GTK_LABEL(m_pPageContents), TRUE ); + gtk_label_set_justify( GTK_LABEL(m_pPageContents), GTK_JUSTIFY_LEFT); + gtk_misc_set_alignment( GTK_MISC(m_pPageContents), 0, 1 ); + gtk_misc_set_padding( GTK_MISC(m_pPageContents ), 5, 5); + + g_object_ref( G_OBJECT(m_pPageContents) ); +} + +WelcomePage::~WelcomePage() +{ + g_object_unref( G_OBJECT(m_pPageContents) ); +} + +void WelcomePage::update() +{ +} diff --git a/crashrep/source/unx/interface.hxx b/crashrep/source/unx/interface.hxx new file mode 100755 index 000000000..9b7a56369 --- /dev/null +++ b/crashrep/source/unx/interface.hxx @@ -0,0 +1,158 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> + +#include <hash_map> +#include <vector> +#include <string> + +class WizardDialog; + +// returns success, on true application will quit +bool save_crash_report( const std::string& rFileName, const std::hash_map< std::string, std::string >& rSettings ); +// returns success, on true application will quit +bool send_crash_report( WizardDialog &rDialog, const std::hash_map< std::string, std::string >& rSettings ); +// must return a valid UTF8 string containing the message that will be sent +std::string crash_get_details( const std::hash_map< std::string, std::string >& rSettings ); + +class StringResource +{ +public: + static void init( int argc, char** argv ); + static const char* get( const char* pKey ); +}; + +class WizardPage +{ +protected: + std::string m_aWizardTitle; + GtkWidget* m_pPageContents; + WizardDialog* m_pDialog; +public: + WizardPage( WizardDialog* pDialog ) : m_pDialog( pDialog ) {} + virtual ~WizardPage(); + + const char* getTitle() const { return m_aWizardTitle.c_str(); } + GtkWidget* getContents() const { return m_pPageContents; } + + virtual void update() = 0; +}; + +class WizardDialog +{ + std::vector< WizardPage* > m_aPages; + int m_nCurrentPage; + + GtkWidget* m_pTopLevel; + GtkWidget* m_pVBox; + GtkWidget* m_pViewPort; + GtkWidget* m_pWizardTitle; + GtkWidget* m_pPageArea; + GtkWidget* m_pSeparator; + GtkWidget* m_pButtonBox; + GtkWidget* m_pBackButton; + GtkWidget* m_pNextButton; + GtkWidget* m_pSendButton; + GtkWidget* m_pCancelButton; + + GtkWidget* m_pStatusDialog; + + std::hash_map< std::string, std::string > m_aSettings; + + static gint button_clicked( GtkWidget* pButton, WizardDialog* pThis ); + + void nextPage(); + void lastPage(); +public: + WizardDialog(); + ~WizardDialog(); + + // takes ownership of page + void insertPage( WizardPage* pPage ); + + void show( bool bShow = true ); + void show_messagebox( const std::string& rMessage ); + gint show_sendingstatus( bool bInProgress ); + void hide_sendingstatus(); + + std::hash_map< std::string, std::string >& getSettings() { return m_aSettings; } + GtkWindow* getTopLevel() const { return GTK_WINDOW(m_pTopLevel); } +}; + +class MainPage : public WizardPage +{ + GtkWidget* m_pInfo; + GtkWidget* m_pEditLabel; + GtkWidget* m_pEdit; + GtkWidget* m_pEntryLabel; + GtkWidget* m_pEntryVBox; + GtkWidget* m_pScrolledEntry; + GtkWidget* m_pEntry; + GtkWidget* m_pHBox; + GtkWidget* m_pRightColumn; + GtkWidget* m_pLeftColumn; + GtkWidget* m_pDetails; + GtkWidget* m_pSave; + GtkWidget* m_pCheck; + GtkWidget* m_pOptions; + GtkWidget* m_pAddressLabel; + GtkWidget* m_pAddress; + + static gint button_clicked( GtkWidget* pButton, MainPage* pThis ); + static gint button_toggled( GtkWidget* pButton, MainPage* pThis ); + +public: + MainPage( WizardDialog* ); + virtual ~MainPage(); + + virtual void update(); +}; + +class WelcomePage : public WizardPage +{ +public: + WelcomePage( WizardDialog* ); + virtual ~WelcomePage(); + + virtual void update(); +}; + +class OptionsDialog +{ + GtkWidget* m_pDialog; + GtkWidget* m_pPage; + GtkWidget* m_pLeftColumn; + GtkWidget* m_pFrame; + GtkWidget* m_pDirect; + GtkWidget* m_pManual; + GtkWidget* m_pServerLabel; + GtkWidget* m_pServer; + GtkWidget* m_pColon; + GtkWidget* m_pPortLabel; + GtkWidget* m_pPort; + GtkWidget* m_pNote; + GtkWidget* m_pOkButton; + GtkWidget* m_pCancelButton; + GtkWidget* m_pButtonBox; + GtkWidget* m_pVBox; + GtkWidget* m_pHBox; + GtkWidget* m_pVBoxServer; + GtkWidget* m_pVBoxPort; + + static gint button_toggled( GtkWidget* pButton, OptionsDialog* pThis ); + +public: + OptionsDialog( GtkWindow* pParent, + std::hash_map< std::string, std::string >& rSettings ); + virtual ~OptionsDialog(); + + std::string getUseProxy(); + std::string getServer(); + std::string getPort(); + +}; diff --git a/crashrep/source/unx/main.cxx b/crashrep/source/unx/main.cxx new file mode 100755 index 000000000..3afcaeaad --- /dev/null +++ b/crashrep/source/unx/main.cxx @@ -0,0 +1,1103 @@ +/************************************************************************* + * + * $RCSfile: main.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: hro $ $Date: 2003-06-06 11:21:57 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <interface.hxx> +#include <cstdio> +#include <sys/utsname.h> +#include <_version.h> +#include <errno.h> +#include <string> +#include <string.h> +#include <assert.h> + +#include <sys/socket.h> +#include <netdb.h> +#include <unistd.h> +#include <pwd.h> +#include <pthread.h> + +#ifdef LINUX +#include <netinet/in.h> +#endif + +typedef int SOCKET; + +#define closesocket close +#define SOCKET_ERROR -1 + +#ifdef SOLARIS +const char *basename( const char *filename ) +{ + const char *pSlash = strrchr( filename, '/' ); + + return pSlash ? pSlash + 1 : pSlash; +} +#endif + +using namespace std; + +static g_bDebugMode = false; +static int g_signal = 0; + +static string g_strReportServer; +static unsigned short g_uReportPort = 80; +static string g_buildid; +static string g_strDefaultLanguage; +static string g_strXMLFileName; +static string g_strPStackFileName; +static string g_strProgramDir; + +static char g_szStackFile[L_tmpnam] = ""; +static char g_szDescriptionFile[2048] = ""; +static char g_szReportFile[2048] = ""; + +#define SO_CRASHREPORT_MAIL "so-report@sun.com" +#define PSTACK_CMD "pstack %d" +#define PSTACKBIN_CMD "pstack.bin %d" + +#ifdef LINUX +#define PMAP_CMD "cat /proc/%d/maps" +#else +#define PMAP_CMD "pmap %d" +#endif + +#define REPORT_SERVER (g_strReportServer.c_str()) +#define REPORT_PORT g_uReportPort + +static string getprogramdir() +{ + return g_strProgramDir; +} + +static const char *getlocale() +{ + const char * locale = getenv( "LC_ALL" ); + + if( NULL == locale ) + locale = getenv( "LC_CTYPE" ); + + if( NULL == locale ) + locale = getenv( "LANG" ); + + if( NULL == locale ) + locale = "C"; + + return locale; +} + +static const char *get_user_name() +{ + struct passwd *ppwd = getpwuid( getuid() ); + + return ppwd ? (ppwd->pw_name ? ppwd->pw_name : "") : ""; +} + +static const char *get_home_dir() +{ + struct passwd *ppwd = getpwuid( getuid() ); + + return ppwd ? (ppwd->pw_dir ? ppwd->pw_dir : "/") : "/"; +} + +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 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 *fpout, FILE *fpin ) +{ + char buffer[1024]; + size_t nBytes; + size_t nBytesWritten = 0; + + while ( 0 != (nBytes = fread( buffer, 1, sizeof(buffer), fpin )) ) + { + nBytesWritten += fwrite( buffer, 1, nBytes, fpout ); + } + + return nBytesWritten; +} + +/* + writes the report to a temp-file + from which it can be reviewed and sent +*/ +bool write_stack( long pid ) +{ + bool bSuccess = false; + + if ( pid ) + { + char *stmp= tmpnam( g_szStackFile ); + FILE *fout, *fin; + char buf[1024]; + + /* open mailfile */ + fout = fopen(stmp, "w"); + + if ( fout ) + { + char cmdbuf[1024]; + + fputs( "<***stacks***>\n", fout ); + + if ( !g_strPStackFileName.length() ) + { + + snprintf(cmdbuf, 1024, PSTACK_CMD, pid); + fin = popen(cmdbuf, "r"); + + if ( fin ) + { + while (fgets(buf, 1024, fin) != NULL) + { + bSuccess = true; + fputs(buf, fout); + } + pclose( fin ); + + } + + if ( !bSuccess ) + { + snprintf(cmdbuf, 1024, PSTACKBIN_CMD, pid); + fin = popen(cmdbuf, "r"); + + if ( fin ) + { + while (fgets(buf, 1024, fin) != NULL) + { + bSuccess = true; + fputs(buf, fout); + } + pclose( fin ); + + } + } + + } + else + { + fin = fopen( g_strPStackFileName.c_str(), "r" ); + if ( fin ) + { + bSuccess = true; + fcopy( fout, fin ); + fclose( fin ); + } + } + + fputs( "</***stacks***>\n", fout ); + + if ( bSuccess ) + { + fputs( "<***maps***>\n", fout ); + bSuccess = false; + + snprintf(cmdbuf, 1024, PMAP_CMD, pid); + fin = popen(cmdbuf, "r"); + + if ( fin ) + { + while (fgets(buf, 1024, fin) != NULL) + { + bSuccess = true; + fputs(buf, fout); + } + pclose( fin ); + + } + fputs( "</***maps***>\n", fout ); + } + + fclose ( fout ); + + } + } + + + return bSuccess; +} + + +bool write_report( const hash_map< string, string >& rSettings ) +{ + FILE *fp = fopen( tmpnam( g_szReportFile ), "w" ); + const char *pszUserType = getenv( "STAROFFICE_USERTYPE" ); + const char *pszProductName = getenv( "PRODUCTNAME" ); + + 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\" uid=\"%s\" usertype=\"%s\">\n" + "<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.0\" feedback=\"%s\" email=\"%s\">\n" + "<reportmail:title>%s</reportmail:title>\n" + "<reportmail:attachment name=\"description.txt\" media-type=\"text/plain\" class=\"UserComment\"/>\n" + "<reportmail:attachment name=\"stack.txt\" media-type=\"text/plain\" class=\"pstack output\"/>\n" + "</reportmail:mail>\n" + "<officeinfo:officeinfo xmlns:officeinfo=\"http://openoffice.org/2002/officeinfo\" build=\"%s\" platform=\"%s\" language=\"%s\" exceptiontype=\"%d\" product=\"%s\" procpath=\"%s\"/>\n" + , + get_user_name(), + pszUserType ? pszUserType : "", + xml_encode(rSettings.find( "CONTACT" )->second).c_str(), + xml_encode(rSettings.find( "EMAIL" )->second).c_str(), + xml_encode(rSettings.find( "TITLE" )->second).c_str(), + g_buildid.length() ? g_buildid.c_str() : "unknown", + _INPATH, + g_strDefaultLanguage.c_str(), + g_signal, + pszProductName ? pszProductName : "unknown", + getprogramdir().c_str() + ); + + struct utsname info; + + memset( &info, 0, sizeof(info) ); + uname( &info ); + + fprintf( fp, + "<systeminfo:systeminfo xmlns:systeminfo=\"http://openoffice.org/2002/systeminfo\">\n" + "<systeminfo:System name=\"%s\" version=\"%s\" build=\"%s\" locale=\"%s\"/>\n" + , + info.sysname, + info.version, + info.release, + getlocale() + ); + fprintf( fp, "<systeminfo:CPU type=\"%s\"/>\n", info.machine ); + fprintf( fp, "</systeminfo:systeminfo>\n" ); + + FILE *fpxml = fopen( g_strXMLFileName.c_str(), "r" ); + if ( fpxml ) + { + fcopy( fp, fpxml ); + fclose( fpxml ); + } + fprintf( fp, "</errormail:errormail>\n" ); + + fclose( fp ); + + return true; +} + + +bool write_description( const hash_map< string, string >& rSettings ) +{ + bool bSuccess = false; + FILE *fp = fopen( tmpnam( g_szDescriptionFile ), "w" ); + + if ( fp ) + { + bSuccess = true; + fprintf( fp, "\xEF\xBB\xBF" ); + fprintf( fp, "%s\n", rSettings.find( "DESCRIPTION" )->second.c_str() ); + fclose( fp ); + } + + return bSuccess; +} + + +static void printSettings( const hash_map<string,string>& rSettings ) +{ + printf( "Settings:\n" ); + for( hash_map<string,string>::const_iterator it = rSettings.begin(); it != rSettings.end(); ++it ) + { + printf( "%s=\"%s\"\n", it->first.c_str(), it->second.c_str() ); + } +} + +bool save_crash_report( const string& rFileName, const hash_map< string, string >& rSettings ) +{ + bool bSuccess = false; + FILE *fpout = fopen( rFileName.c_str(), "w" ); + + if ( fpout ) + { + FILE *fpin = fopen( g_szStackFile, "r" ); + + if ( fpin ) + { + char buf[1024]; + + while (fgets(buf, sizeof(buf), fpin) != NULL) + { + fputs(buf, fpout); + } + + bSuccess = true; + + fclose ( fpin ); + } + + fclose( fpout ); + } + + 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 ( g_bDebugMode ) + { + printf( "*** Sending HTTP request ***\n\n" ); + printf( buffer ); + } + + if ( SOCKET_ERROR != send( s, buffer, strlen(buffer), 0 ) ) + { + size_t nBytes; + + do + { + nBytes = fread( buffer, 1, sizeof(buffer), fp ); + + if ( nBytes ) + { + if ( g_bDebugMode ) + fwrite( buffer, 1, nBytes, stdout ); + success = SOCKET_ERROR != send( s, buffer, nBytes, 0 ); + } + } while( nBytes && success ); + + if ( success ) + { + if ( g_bDebugMode ) + printf( "*** Receiving HTTP response ***\n\n" ); + + 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; + } + if ( g_bDebugMode ) + do + { + printf( buffer ); + memset( buffer, 0, sizeof(buffer) ); + } while ( 0 < recv( s, buffer, sizeof(buffer), 0 ) ); + } + } + + } + + 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_szReportFile, "r" ); + if ( fpin ) + { + fprintf( fp, + "<item>\n" + "<key xsi:type=\"xsd:string\">reportmail.xml</key>\n" + "<value xsi:type=\"xsd:string\"><![CDATA[" ); + fcopy( fp, fpin ); + fprintf( fp, "]]></value></item>\n" ); + fclose( fpin ); + } + + fpin = fopen( g_szDescriptionFile, "r" ); + if ( fpin ) + { + fprintf( fp, + "<item>\n" + "<key xsi:type=\"xsd:string\">description.txt</key>\n" + "<value xsi:type=\"xsd:string\"><![CDATA[" ); + fcopy( fp, fpin ); + fprintf( fp, "]]></value></item>\n" ); + fclose( fpin ); + }; + + fpin = fopen( g_szStackFile, "r" ); + if ( fpin ) + { + fprintf( fp, + "<item>\n" + "<key xsi:type=\"xsd:string\">description.txt</key>\n" + "<value xsi:type=\"xsd:string\"><![CDATA[" ); + fcopy( fp, fpin ); + fprintf( fp, "]]></value></item>\n" ); + 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 *pServer; + unsigned short uPort; + const char *pProxyServer; + unsigned short uProxyPort; + WizardDialog *pDialog; +}; + +extern "C" void *http_send_thread( void *arg ) +{ + RequestParams *request = (RequestParams *)arg; + + int oldtype; + + /* Killing me hardly ;-) */ + pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype ); + + request->success = SendHTTPRequest( + request->fpin, + request->pServer, + request->uPort, + request->pProxyServer, + request->uProxyPort + ); + + request->pDialog->hide_sendingstatus(); + + return 0; +} + +bool SendAsyncHTTPRequest( + WizardDialog &rDialog, + FILE *fp, + const char *pszServer, + unsigned short uPort = 80, + const char *pszProxyServer = NULL, + unsigned short uProxyPort = 8080 ) +{ + RequestParams request; + + request.success = false; + request.pDialog = &rDialog; + request.fpin = fp; + request.pServer = pszServer; + request.uPort = uPort; + request.pProxyServer = pszProxyServer; + request.uProxyPort = uProxyPort; + + pthread_t thread = 0; + + if ( + 0 == pthread_create ( + &thread, + NULL, + http_send_thread, + (void*)&request ) + ) + { + gint response = rDialog.show_sendingstatus( TRUE ); + + pthread_cancel( thread ); + + void *thread_result = NULL; + + pthread_join( thread, &thread_result ); + } + + return request.success; +} + +bool send_crash_report( WizardDialog &rDialog, const hash_map< string, string >& rSettings ) +{ + if ( 0 == strcasecmp( rSettings.find( "CONTACT" )->second.c_str(), "true" ) && + !trim_string(rSettings.find( "EMAIL" )->second).length() ) + { + rDialog.show_messagebox( StringResource::get( "%ERROR_MSG_NOEMAILADDRESS%" ) ); + return false; + } + + char *endptr = NULL; + + const char *pProxyServer = rSettings.find( "SERVER" )->second.c_str(); + unsigned short uProxyPort = (unsigned short)strtoul( rSettings.find( "PORT" )->second.c_str(), &endptr, 10 ); + + bool bUseProxy = !strcasecmp( "true", rSettings.find( "USEPROXY" )->second.c_str() ); + + + write_description( rSettings ); + write_report( rSettings ); + + bool bSuccess = false; + + FILE *fptemp = tmpfile(); + if ( fptemp ) + { + WriteSOAPRequest( fptemp ); + fseek( fptemp, 0, SEEK_SET ); + + /* + bSuccess = SendHTTPRequest( + fptemp, + REPORT_SERVER, REPORT_PORT, + bUseProxy ? pProxyServer : NULL, + uProxyPort ? uProxyPort : 8080 + ); + */ + + bSuccess = SendAsyncHTTPRequest( + rDialog, + fptemp, + REPORT_SERVER, REPORT_PORT, + bUseProxy ? pProxyServer : NULL, + uProxyPort ? uProxyPort : 8080 + ); + + fclose( fptemp ); + + if ( bSuccess ) + rDialog.show_sendingstatus( FALSE ); + else + rDialog.show_messagebox( StringResource::get( "%ERROR_MSG_PROXY%" ) ); + } + else + rDialog.show_messagebox( "%ERROR_MSG_DISK_FULL%" ); + + unlink( g_szDescriptionFile ); + unlink( g_szReportFile ); + + return bSuccess; +} + + +static bool append_file( const char *filename, string& rString ) +{ + char buf[1024]; + bool bSuccess = false; + + FILE *fp = fopen( filename, "r" ); + if ( fp ) + { + bSuccess = true; + while (fgets(buf, sizeof(buf), fp) != NULL) + { + rString.append( buf ); + } + fclose( fp ); + } + + return true; +} + +string crash_get_details( const hash_map< string, string >& rSettings ) +{ + string aRet; + + FILE *fp; + char buf[1024]; + + write_description( rSettings ); + write_report( rSettings ); + + aRet.append( rSettings.find( "TITLE" )->second.c_str() ); + aRet.append( "\n\n" ); + append_file( g_szDescriptionFile, aRet ); + aRet.append( "\n\n-------\n\n" ); + append_file( g_szReportFile, aRet ); + aRet.append( "\n\n-------\n\n" ); + append_file( g_szStackFile, aRet ); + + unlink( g_szDescriptionFile ); + unlink( g_szReportFile ); + + return aRet; +} + + +// ensure validity of program relative paths +static void setup_program_dir( const char* progname ) +{ + string aDir = progname; + size_t pos = aDir.rfind( '/' ); + // FIXME: search PATH if necessary + assert( pos != string::npos ); + g_strProgramDir = aDir.substr( 0, pos + 1 ); + aDir.erase( pos ); + chdir( aDir.c_str() ); +} + +//************************************************************************* + +static long setup_commandline_arguments( int argc, char** argv, int *pSignal ) +{ + long pid = 0; + int signal = 0; + + for ( int n = 1; n < argc; n++ ) + { + if ( 0 == strcmp( argv[n], "-p" ) ) + { + if ( ++n < argc ) + pid = strtol( argv[n], NULL, 0 ); + } + else if ( 0 == strcmp( argv[n], "-s" ) ) + { + if ( ++n < argc ) + signal = strtol( argv[n], NULL, 0 ); + } + else if ( 0 == strcmp( argv[n], "-debug" ) ) + { + g_bDebugMode = true; + } + else if ( 0 == strcmp( argv[n], "-xml" ) ) + { + if ( ++n < argc ) + g_strXMLFileName = argv[n]; + } + else if ( 0 == strcmp( argv[n], "-stack" ) ) + { + if ( ++n < argc ) + g_strPStackFileName = argv[n]; + } + else if ( argv[n] && strlen(argv[n]) ) + { + printf( + "\n%s crash_report %s\n\n" \ + "/?, -h[elp] %s\n\n" \ + "%-20s %s\n\n", + StringResource::get( "%MSG_CMDLINE_USAGE%" ), + StringResource::get( "%MSG_PARAM_PROCESSID%" ), + StringResource::get( "%MSG_PARAM_HELP_DESCRIPTION%" ), + StringResource::get( "%MSG_PARAM_PROCESSID%" ), + StringResource::get( "%MSG_PARAM_PROCESSID_DESCRIPTION%" ) + ); + break; + } + } + + *pSignal = signal; + + return pid; +} + +//************************************************************************* + +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, "r" ); + 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( iEqualSign + 1, -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 == strcasecmp( keyname.c_str(), pKeyName ) ) + { + retValue = value; + break; + } + } + } + + fclose( fp ); + } + + return retValue; +} + +static string get_profile_string( const char *pFileName, const char *pSectionName, const char *pKeyName, const char *pDefault = NULL ) +{ + FILE *fp = fopen( pFileName, "r" ); + string retValue = pDefault ? pDefault : ""; + + if ( fp ) + { + string line; + string section; + + while ( read_line( fp, line ) ) + { + line = trim_string( line ); + + if ( line.length() && line[0] == '[' ) + { + line.erase( 0, 1 ); + string::size_type end = line.find( ']', 0 ); + + if ( string::npos != end ) + section = trim_string( line.substr( 0, end ) ); + } + else + { + + 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( iEqualSign + 1, -1 ); + value = trim_string( value ); + + if ( + 0 == strcasecmp( section.c_str(), pSectionName ) && + 0 == strcasecmp( keyname.c_str(), pKeyName ) + ) + { + retValue = value; + break; + } + } + } + } + + fclose( fp ); + } + + return retValue; +} + +#define RCFILE ".crash_reportrc" + +static bool write_settings( const hash_map< string, string >& rSettings ) +{ + bool success = false; + string sRCFile = get_home_dir(); + + sRCFile += "/"; + sRCFile += string(RCFILE); + + FILE *fp = fopen( sRCFile.c_str(), "w" ); + + if ( fp ) + { + fprintf( fp, "[Options]\n" ); + fprintf( fp, "UseProxy=%s\n", rSettings.find( "USEPROXY" )->second.c_str() ); + fprintf( fp, "ProxyServer=%s\n", rSettings.find( "SERVER" )->second.c_str() ); + fprintf( fp, "ProxyPort=%s\n", rSettings.find( "PORT" )->second.c_str() ); + fprintf( fp, "ReturnAddress=%s\n", rSettings.find( "EMAIL" )->second.c_str() ); + fprintf( fp, "AllowContact=%s\n", rSettings.find( "CONTACT" )->second.c_str() ); + fclose( fp ); + } + + return success; +} + +static void read_settings( hash_map< string, string >& rSettings ) +{ + string sRCFile = get_home_dir(); + + sRCFile += "/"; + sRCFile += string(RCFILE); + + rSettings[ "EMAIL" ] = get_profile_string( sRCFile.c_str(), "Options", "ReturnAddress" ); + rSettings[ "SERVER" ] = get_profile_string( sRCFile.c_str(), "Options", "ProxyServer" ); + rSettings[ "PORT" ] = get_profile_string( sRCFile.c_str(), "Options", "ProxyPort" ); + rSettings[ "USEPROXY" ] = get_profile_string( sRCFile.c_str(), "Options", "UseProxy" ); + rSettings[ "CONTACT" ] = get_profile_string( sRCFile.c_str(), "Options", "AllowContact" ); +} + +static bool setup_version() +{ + if ( !getenv( "PRODUCTNAME" ) ) + { + string productkey = get_profile_string( "bootstraprc", "Bootstrap", "ProductKey" ); + + if ( productkey.length() ) + { + static string productname; + static string productversion; + string::size_type iSpace = productkey.find( ' ', 0 ); + + if ( string::npos != iSpace ) + { + productname = productkey.substr( 0, iSpace ); + productversion = productkey.substr( iSpace + 1, -1 ); + } + else + productname = productkey; + + productname.insert( 0, "PRODUCTNAME=" ); + putenv( (char *)productname.c_str() ); + + productversion.insert( 0, "PRODUCTVERSION=" ); + putenv( (char *)productversion.c_str() ); + } + } + + g_buildid = get_profile_string( "bootstraprc", "Bootstrap", "BuildId" ); + g_strDefaultLanguage = get_script_string( "instdb.ins", "DefaultLanguage" ); + + g_strReportServer = get_profile_string( "bootstraprc", "ErrorReport", "Server" ); + + string strReportPort = get_profile_string( "bootstraprc", "ErrorReport", "Port", "80" ); + char *endptr = NULL; + unsigned short uReportPort = (unsigned short)strtoul( strReportPort.c_str(), &endptr, 10 ); + g_uReportPort = uReportPort ? uReportPort : 80; + + return 0 != g_strReportServer.length(); +} + +int main( int argc, char** argv ) +{ + freopen( "/dev/null", "w", stderr ); + + if ( setup_version() ) + { + gtk_set_locale (); + gtk_init (&argc, &argv); + + StringResource::init( argc, argv ); + + setup_program_dir( argv[0] ); + + long pid = setup_commandline_arguments( argc, argv, &g_signal ); + + if ( write_stack( pid ) ) + { + WizardDialog aDialog; + + hash_map< string, string >& rDialogSettings = aDialog.getSettings(); + + read_settings( rDialogSettings ); + + aDialog.insertPage( new WelcomePage( &aDialog ) ); + aDialog.insertPage( new MainPage( &aDialog ) ); + + aDialog.show(); + + gtk_main(); + + write_settings( rDialogSettings ); + + unlink( g_szStackFile ); + + return 0; + } + } + + return -1; +} diff --git a/crashrep/source/unx/makefile.mk b/crashrep/source/unx/makefile.mk new file mode 100755 index 000000000..46f9fbc81 --- /dev/null +++ b/crashrep/source/unx/makefile.mk @@ -0,0 +1,101 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1 $ +# +# last change: $Author: hro $ $Date: 2003-06-06 11:21:58 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (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.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=crashrep +TARGET=crash_report.bin +TARGETTYPE=CUI + +ENABLE_EXCEPTIONS=TRUE +LIBTARGET=NO +LIBSALCPPRT=$(0) + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +# ------------------------------------------------------------------ + +CFLAGS+=`pkg-config --cflags gtk+-2.0` + +OBJFILES=\ + $(OBJ)$/interface.obj \ + $(OBJ)$/res.obj \ + $(OBJ)$/main.obj + +APP1NOSAL=TRUE +APP1TARGET=$(TARGET) +APP1OBJS=$(OBJFILES) +.IF "$(COM)" == "GCC" +APP1STDLIBS=-Wl,-Bstatic `pkg-config --only-mod-libs --libs gtk+-2.0` -lpng -lzlib -ljpeg -ltiff -Wl,-Bdynamic -lXext -lX11 -ldl -lnsl +.ELSE +APP1STDLIBS=-Bstatic `pkg-config --only-mod-libs --libs gtk+-2.0` -lpng -lzlib -ljpeg -ltiff -Bdynamic -lXext -lX11 -ldl -lsocket -lnsl +.ENDIF + +ALL: ALLTAR $(BIN)$/crash_dump.res.01 + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +$(BIN)$/crash_dump.res.01: ..$/all$/crashrep.lng + $(BIN)$/unxcrashres ..$/all$/crashrep.lng $(BIN)$/crash_dump.res diff --git a/crashrep/source/unx/res.cxx b/crashrep/source/unx/res.cxx new file mode 100755 index 000000000..e72a01ac4 --- /dev/null +++ b/crashrep/source/unx/res.cxx @@ -0,0 +1,108 @@ +#if OSL_DEBUG_LEVEL == 0 +#define NDEBUG +#endif +#include <assert.h> + +#include <interface.hxx> +#include <cstdio> +#include <hash_map> +#include <string> + +using namespace std; + +static hash_map< string, string >* pStringResources = NULL; + +static string getResFileName( const char* progname ) +{ + string aRet = progname; + size_t pos = aRet.rfind( '/' ); + // FIXME: search PATH if necessary + assert( pos != string::npos ); + aRet.erase( pos ); + aRet.append( "/resource/crash_dump.res" ); + + return aRet; +} + +static void filterString( string& rString ) +{ + static const char* pProductName = getenv( "PRODUCTNAME" ); + static int nProductLen = pProductName ? strlen( pProductName ) : 0; + static const char* pProductVersion = getenv( "PRODUCTVERSION" ); + static int nVersionLen = pProductVersion ? strlen( pProductVersion ) : 0; + + // fill in eventually escaped characters + string::size_type pos = 0; + while( (pos = rString.find( '\\' ) ) != string::npos ) + { + char cRep = 0; + switch( rString[pos+1] ) + { + case 't': cRep = '\t';break; + case 'n': cRep = '\n';break; + case 'r': cRep = '\r';break; + case 'f': cRep = '\f';break; + default: cRep = rString[pos+1]; + } + if( cRep ) + rString.replace( pos, 2, &cRep, 1 ); + } + while( (pos = rString.find( '~' ) ) != string::npos ) + { + // replace mnemonic marker + rString.replace( pos, 1, "_", 1 ); + } + while( (pos = rString.find( "%PRODUCTNAME%" ) ) != string::npos ) + { + rString.replace( pos, 13, pProductName ? pProductName : "OpenOffice" ); + } + while( (pos = rString.find( "%PRODUCTVERSION%" ) ) != string::npos ) + { + rString.replace( pos, 16, pProductVersion ? pProductVersion : "" ); + } + // remove whitespace at end + pos = rString.find_last_not_of( "\r\n\t\f " ); + if( pos != string::npos ) + rString.erase( pos+1 ); +} + +void StringResource::init( int argc, char** argv ) +{ + pStringResources = new hash_map< string, string >(); + + string aResFile = getResFileName( argv[0] ); + + FILE* fp = fopen( aResFile.c_str(), "r" ); + if( fp ) + { + char buf[4096]; + string aKey; + string aValue; + while( ! feof( fp ) ) + { + if( ! fgets( buf, sizeof(buf), fp ) ) + break; + + char* pEq = strchr( buf, '=' ); + if( ! pEq || *(pEq+1) == 0 ) // invalid line + continue; + aKey = string(buf, pEq-buf); + aValue = pEq+1; + while( (aValue.empty() || aValue[ aValue.size()-1 ] != '\n') && ! feof( fp ) ) + { + if( fgets( buf, sizeof( buf ), fp ) ) + aValue.append( buf ); + } + filterString( aValue ); + (*pStringResources)[aKey] = aValue; + } + fclose( fp ); + } +} + +const char* StringResource::get( const char* pKey ) +{ + hash_map< string, string >::const_iterator it = pStringResources->find( pKey ); + return (it == pStringResources->end()) ? "" : it->second.c_str(); +} + diff --git a/crashrep/source/unx/res/makefile.mk b/crashrep/source/unx/res/makefile.mk new file mode 100755 index 000000000..a78726715 --- /dev/null +++ b/crashrep/source/unx/res/makefile.mk @@ -0,0 +1,22 @@ +PRJ=..$/..$/.. + +PRJNAME=crashrep +TARGET=unxcrashres +LIBTARGET=NO +TARGETTYPE=CUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + + +# --- Files -------------------------------------------------------- + +APP1TARGET=$(TARGET) +APP1OBJS=$(OBJ)$/unxcrashres.obj +APP1STDLIBS=$(TOOLSLIB) $(SALLIB) + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/crashrep/source/unx/res/unxcrashres.cxx b/crashrep/source/unx/res/unxcrashres.cxx new file mode 100755 index 000000000..e18eb3d27 --- /dev/null +++ b/crashrep/source/unx/res/unxcrashres.cxx @@ -0,0 +1,80 @@ +#include <tools/config.hxx> +#include <rtl/string.hxx> +#include <osl/thread.h> +#include <tools/l2txtenc.hxx> + +#include <hash_map> +#include <string> +#include <cstdio> +#include <cerrno> + +using namespace std; +using namespace rtl; + +void filterValue( ByteString& rValue, const OString& rGroup, const ByteString& rKey ) +{ + USHORT nStartPos = rValue.Search( '"' ); + USHORT nStopPos = rValue.SearchBackward( '"' ); + if( nStartPos == STRING_NOTFOUND || nStopPos == STRING_NOTFOUND ) + { + fprintf( stderr, "Error: invalid key in [%s] in key \"%s\"\n", + rGroup.getStr(), + rKey.GetBuffer() ); + exit( 1 ); + } + rValue.Erase( nStopPos ); + rValue.Erase( 0, nStartPos+1 ); +} + +int main( int argc, char** argv ) +{ + if( argc != 3 ) + { + fprintf( stderr, "USAGE: unxcrashres <in_lng_file> <out_file_prefix>\n" ); + exit( 1 ); + } + + ByteString tmp_argv1( argv[1] ); + Config aConfig( String( tmp_argv1, osl_getThreadTextEncoding() ) ); + hash_map< int, hash_map< OString, OString, OStringHash > > aFiles; + + for( USHORT i = 0; i < aConfig.GetGroupCount(); i++ ) + { + aConfig.SetGroup( aConfig.GetGroupName( i ) ); + OString aGroup = aConfig.GetGroupName( i ); + USHORT nKeys = aConfig.GetKeyCount(); + for( USHORT n = 0; n < nKeys; n++ ) + { + ByteString aKey = aConfig.GetKeyName( n ); + ByteString aValue = aConfig.ReadKey( aKey ); + int nRes = aKey.ToInt32(); + // tailor key + filterValue( aValue, aGroup, aKey ); + + aFiles[nRes][aGroup] = ByteString( String( aValue, Langcode2TextEncoding( (USHORT)nRes ) ), RTL_TEXTENCODING_UTF8 ); + } + } + + for( hash_map< int, hash_map< OString, OString, OStringHash > >::const_iterator lang_it = aFiles.begin(); lang_it != aFiles.end(); ++lang_it ) + { + ByteString aFile( argv[2] ); + aFile.Append( '.' ); + if( lang_it->first < 10 ) + aFile.Append( '0' ); + aFile.Append( ByteString::CreateFromInt32( lang_it->first ) ); + FILE* fp = fopen( aFile.GetBuffer(), "w" ); + if( ! fp ) + { + fprintf( stderr, "Error: could not open \"%s\" for writing: %s\n", + aFile.GetBuffer(), strerror( errno ) ); + exit(1); + } + for( hash_map< OString, OString, OStringHash >::const_iterator line_it = lang_it->second.begin(); line_it != lang_it->second.end(); ++line_it ) + { + fprintf( fp, "%s=%s\n", line_it->first.getStr(), line_it->second.getStr() ); + } + fclose( fp ); + } + + return 0; +} diff --git a/crashrep/source/win32/base64.cpp b/crashrep/source/win32/base64.cpp new file mode 100755 index 000000000..2b311da14 --- /dev/null +++ b/crashrep/source/win32/base64.cpp @@ -0,0 +1,56 @@ +#include <stdio.h> +#include <string.h> +#include "base64.h" + +static const char base64_tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +extern "C" size_t base64_encode( FILE *fin, FILE *fout ) +{ + size_t nBytesRead = 0; + size_t nLineLength = 0; + size_t nBytesWritten = 0; + + size_t nBytes = 0; + + do + { + unsigned char in_buffer[3]; + + memset( in_buffer, 0, sizeof(in_buffer) ); + nBytes = fread( in_buffer, 1, sizeof(in_buffer), fin ); + nBytesRead += nBytes; + + if ( nBytes ) + { + unsigned long value = + ((unsigned long)in_buffer[0]) << 16 | + ((unsigned long)in_buffer[1]) << 8 | + ((unsigned long)in_buffer[2]) << 0; + + unsigned char out_buffer[4]; + + memset( out_buffer, '=', sizeof(out_buffer) ); + + out_buffer[0] = base64_tab[(value >> 18) & 0x3F]; + out_buffer[1] = base64_tab[(value >> 12) & 0x3F]; + + if ( nBytes > 1 ) + { + out_buffer[2] = base64_tab[(value >> 6) & 0x3F]; + if ( nBytes > 2 ) + out_buffer[3] = base64_tab[(value >> 0) & 0x3F]; + } + + if ( nLineLength >= 76 ) + { + fputs( "\n", fout ); + nLineLength = 0; + } + + nBytesWritten += fwrite( out_buffer, 1, sizeof(out_buffer), fout ); + nLineLength += sizeof(out_buffer); + } + } while ( nBytes ); + + return nBytesWritten; +} diff --git a/crashrep/source/win32/base64.h b/crashrep/source/win32/base64.h new file mode 100755 index 000000000..39dd1f88b --- /dev/null +++ b/crashrep/source/win32/base64.h @@ -0,0 +1,19 @@ +#ifndef __BASE64_H +#define __BASE64_H + +#ifndef _INC_STDIO +#include <stdio.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +size_t base64_encode( FILE *fin, FILE *fout ); + +#ifdef __cplusplus +} +#endif + +#endif /* __BASE64_H */ + diff --git a/crashrep/source/win32/ctrylnglist.txt b/crashrep/source/win32/ctrylnglist.txt new file mode 100755 index 000000000..91f633cef --- /dev/null +++ b/crashrep/source/win32/ctrylnglist.txt @@ -0,0 +1,29 @@ +1 LANG_ENGLISH SUBLANG_ENGLISH_US +3 LANG_PORTUGUESE SUBLANG_PORTUGUESE +4 LANG_GERMAN SUBLANG_GERMAN +7 LANG_RUSSIAN SUBLANG_NEUTRAL +30 LANG_GREEK SUBLANG_NEUTRAL +31 LANG_DUTCH SUBLANG_DUTCH +33 LANG_FRENCH SUBLANG_FRENCH +34 LANG_SPANISH SUBLANG_SPANISH +35 LANG_FINNISH SUBLANG_NEUTRAL +36 LANG_HUNGARIAN SUBLANG_NEUTRAL +39 LANG_ITALIAN SUBLANG_ITALIAN +42 LANG_CZECH SUBLANG_NEUTRAL +43 LANG_SLOVAK SUBLANG_NEUTRAL +44 LANG_ENGLISH SUBLANG_ENGLISH_UK +45 LANG_DANISH SUBLANG_NEUTRAL +46 LANG_SWEDISH SUBLANG_SWEDISH +47 LANG_NORWEGIAN SUBLANG_NORWEGIAN_BOKMAL +48 LANG_POLISH SUBLANG_NEUTRAL +49 LANG_GERMAN SUBLANG_NEUTRAL +55 LANG_PORTUGUESE SUBLANG_PORTUGUESE_BRAZILIAN +81 LANG_JAPANESE SUBLANG_NEUTRAL +82 LANG_KOREAN SUBLANG_KOREAN +86 LANG_CHINESE SUBLANG_CHINESE_SIMPLIFIED +88 LANG_CHINESE SUBLANG_CHINESE_TRADITIONAL +90 LANG_TURKISH SUBLANG_NEUTRAL +96 LANG_ARABIC SUBLANG_NEUTRAL +97 LANG_HEBREW SUBLANG_NEUTRAL +37 LANG_CATALAN SUBLANG_NEUTRAL +66 LANG_THAI SUBLANG_NEUTRAL diff --git a/crashrep/source/win32/makefile.mk b/crashrep/source/win32/makefile.mk new file mode 100755 index 000000000..c18aef4c4 --- /dev/null +++ b/crashrep/source/win32/makefile.mk @@ -0,0 +1,117 @@ +#************************************************************************* +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.1 $ +# +# last change: $Author: hro $ $Date: 2003-06-06 11:22:04 $ +# +# The Contents of this file are made available subject to the terms of +# either of the following licenses +# +# - GNU Lesser General Public License Version 2.1 +# - Sun Industry Standards Source License Version 1.1 +# +# Sun Microsystems Inc., October, 2000 +# +# GNU Lesser General Public License Version 2.1 +# ============================================= +# Copyright 2000 by Sun Microsystems, Inc. +# 901 San Antonio Road, Palo Alto, CA 94303, USA +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1, as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# Sun Industry Standards Source License Version 1.1 +# ================================================= +# The contents of this file are subject to the Sun Industry Standards +# Source License Version 1.1 (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.openoffice.org/license.html. +# +# Software provided under this License is provided on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +# WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, +# MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. +# See the License for the specific provisions governing your rights and +# obligations concerning the Software. +# +# The Initial Developer of the Original Code is: Sun Microsystems, Inc. +# +# Copyright: 2000 by Sun Microsystems, Inc. +# +# All Rights Reserved. +# +# Contributor(s): _______________________________________ +# +# +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=crashrep +TARGET=soreport +LIBTARGET=NO +ENABLE_EXCEPTIONS=TRUE +TARGETTYPE=GUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Resources ---------------------------------------------------- + +RCFILES=$(TARGET).rc + +# --- Files -------------------------------------------------------- + +OBJFILES=\ + $(OBJ)$/soreport.obj\ + $(OBJ)$/mapi.obj\ + $(OBJ)$/base64.obj + +LNGFILES=..$/all$/crashrep.lng + +APP1OBJS=$(OBJFILES) + +APP1NOSAL=TRUE + +APP1TARGET=$(TARGET) + +STDLIB1=\ + gdi32.lib\ + comctl32.lib\ + comdlg32.lib\ + advapi32.lib\ + wsock32.lib\ + dbghelp.lib + +APP1NOSVRES=$(RES)$/$(TARGET).res + +ALLTAR: $(BIN)$/$(TARGET).exe.manifest + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +# Generate the native Windows resource file +# using lngconvex.exe + +$(RCFILES) : $(LNGFILES) makefile.mk rcfooter.txt rcheader.txt rctemplate.txt ctrylnglist.txt + +lngconvex.exe -lng ..\all\crashrep.lng -rc $(TARGET).rc -c ctrylnglist.txt -rct rctemplate.txt -rch rcheader.txt -rcf rcfooter.txt + +$(BIN)$/$(TARGET).exe.manifest: soreport.manifest + +$(COPY) $< $@ diff --git a/crashrep/source/win32/rcfooter.txt b/crashrep/source/win32/rcfooter.txt new file mode 100755 index 000000000..43c268ca9 --- /dev/null +++ b/crashrep/source/win32/rcfooter.txt @@ -0,0 +1 @@ +// Footer
\ No newline at end of file diff --git a/crashrep/source/win32/rcheader.txt b/crashrep/source/win32/rcheader.txt new file mode 100755 index 000000000..fcd71a15c --- /dev/null +++ b/crashrep/source/win32/rcheader.txt @@ -0,0 +1,4 @@ +// Header +#include "resource.h" +#include "winres.h" + diff --git a/crashrep/source/win32/rctemplate.txt b/crashrep/source/win32/rctemplate.txt new file mode 100755 index 000000000..a0572063d --- /dev/null +++ b/crashrep/source/win32/rctemplate.txt @@ -0,0 +1,168 @@ +LANGUAGE %LANGUAGE% , %SUBLANGUAGE% + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_WELCOME_PAGE DIALOGEX 0, 41, 327, 195 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "",IDC_RICHEDIT21,"RICHEDIT20W",TCS_RAGGEDRIGHT | ES_READONLY | + TCS_MULTISELECT | WS_VSCROLL,7,7,313,151 +END + +IDD_REPORT_PAGE DIALOGEX 0, 41, 327, 195 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "1",IDC_REPORT_INTRO,7,7,313,48 + LTEXT "2",IDC_ENTER_TITLE,7,58,233,8 + EDITTEXT IDC_EDIT_TITLE,7,68,235,14,ES_AUTOHSCROLL + LTEXT "3",IDC_ENTER_DESCRIPTION,7,86,316,8 + EDITTEXT IDC_EDIT_DESCRIPTION,7,97,235,49,ES_MULTILINE | + ES_WANTRETURN | WS_VSCROLL + CONTROL "4",IDC_ALLOW_CONTACT,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,148,303,10 + LTEXT "4a",IDC_LABEL_EMAIL,18,162,226, + 8 + EDITTEXT IDC_EDIT_EMAIL,17,173,224,14,ES_AUTOHSCROLL + PUSHBUTTON "5",IDC_SHOW_REPORT,249,94,74,14 + PUSHBUTTON "6",IDC_OPTIONS,249,116,74,14 + PUSHBUTTON "7",IDC_SAVE_REPORT,249,138,74,14 +END + +IDD_DIALOG_FRAME DIALOGEX 0, 0, 331, 265 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | + DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "1" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "",IDC_STATIC,0,0,331,40 + CONTROL "",IDC_HEADER,"RICHEDIT20W",TCS_VERTICAL | TCS_MULTISELECT | ES_READONLY, + 7,7,316,33 + PUSHBUTTON "1",IDBACK,155,244,50,14 + PUSHBUTTON "2",IDNEXT,214,244,50,14 + PUSHBUTTON "3",IDFINISH,214,244,50,14 + PUSHBUTTON "4",IDCANCEL,273,244,50,14 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,40,331,1 + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,237,331,1 +END + +IDD_PREVIEW_FRAME DIALOGEX 0, 0, 251, 185 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | + DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | + WS_SIZEBOX +CAPTION "1" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "",IDC_EDIT_PREVIEW,"RICHEDIT20W",ES_MULTILINE | + ES_AUTOVSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | WS_HSCROLL | + TCS_MULTISELECT | ES_READONLY | TCS_RAGGEDRIGHT | + WS_BORDER + , + 7,7,237,150 + DEFPUSHBUTTON "4",IDOK,193,164,50,14 +END + + +IDD_OPTIONS_FRAME DIALOGEX 0, 0, 295, 182 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "1" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "1",IDC_PROXY_SETTINGS,7,7,222,92 + CONTROL "2",IDC_RADIO_SYSTEM,"Button",BS_AUTORADIOBUTTON,15,27, + 208,10 + CONTROL "3",IDC_RADIO_DIRECT,"Button",BS_AUTORADIOBUTTON,15,39, + 208,10 + CONTROL "4",IDC_RADIO_MANUAL,"Button",BS_AUTORADIOBUTTON,15,51, + 208,10 + LTEXT "5",IDC_LABEL_PROXYSERVER,27,64,148,8 + EDITTEXT IDC_EDIT_PROXYSERVER,27,76,148,14,ES_AUTOHSCROLL + LTEXT ":",IDC_STATIC,178,78,8,8 + LTEXT "6",IDC_LABEL_PROXYPORT,184,64,40,8 + EDITTEXT IDC_EDIT_PROXYPORT,184,76,40,14,ES_AUTOHSCROLL | + ES_NUMBER + DEFPUSHBUTTON "7",IDOK,238,7,50,14 + PUSHBUTTON "8",IDCANCEL,238,26,50,14 + CONTROL "",IDC_PROXY_DESCRIPTION,"RichEdit20W",ES_MULTILINE | + ES_READONLY | WS_VSCROLL,7,106,281,69 +END + +IDD_SENDING_STATUS DIALOGEX 0, 0, 216, 73 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "1" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + PUSHBUTTON "2",IDCANCEL,159,52,50,14 + LTEXT "3",IDC_SENDING_REPORT_STATUS,7,7,202,34 +END + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_WELCOME_CAPTION %WELCOME_CAPTION% + IDS_WELCOME_HEADER %WELCOME_HEADER% + IDS_WELCOME_BODY1 %WELCOME_BODY1% + IDS_WELCOME_BODY2 %WELCOME_BODY2% + IDS_WELCOME_BODY3 %WELCOME_BODY3% + IDS_PRIVACY_URL %PRIVACY_URL% + IDS_NEXT_BUTTON %NEXT_BUTTON% + IDS_CANCEL_BUTTON %CANCEL_BUTTON% + IDS_OK_BUTTON %OK_BUTTON% +END + +STRINGTABLE +BEGIN + IDS_REPORT_CAPTION %REPORT_CAPTION% + IDS_REPORT_HEADER %REPORT_HEADER% + IDS_REPORT_INTRO %REPORT_BODY% + IDS_ENTER_TITLE %ENTER_TITLE% + IDS_ALLOW_CONTACT %ALLOW_CONTACT% + IDS_ENTER_DESCRIPTION %ENTER_DESCRIPTION% + IDS_BACK_BUTTON %BACK_BUTTON% + IDS_SEND_BUTTON %SEND_BUTTON% + IDS_DONOT_SEND_BUTTON %DONOT_SEND_BUTTON% + IDS_SHOW_REPORT_BUTTON %SHOW_REPORT_BUTTON% + IDS_SAVE_REPORT_BUTTON %SAVE_REPORT_BUTTON% + IDS_OPTIONS_BUTTON %OPTIONS_BUTTON% + IDS_LABEL_EMAIL %ENTER_EMAIL% +END + +STRINGTABLE +BEGIN + IDS_ERROR_MSG_SIMPLE_MAPI %ERROR_MSG_SIMPLE_MAPI% + IDS_ERROR_MSG_DISK_FULL %ERROR_MSG_DISK_FULL% + IDS_ERROR_MSG_PROXY %ERROR_MSG_PROXY% + IDS_ERROR_MSG_NOCONNECT %ERROR_MSG_NOCONNECT% + IDS_ERROR_MSG_NOEMAILADDRESS %ERROR_MSG_NOEMAILADDRESS% + IDS_SENDING_REPORT_HEADER %SENDING_REPORT_HEADER% + IDS_SENDING_REPORT_STATUS %SENDING_REPORT_STATUS% + IDS_SENDING_REPORT_STATUS_FINISHED %SENDING_REPORT_STATUS_FINISHED% + IDS_MSG_CMDLINE_USAGE %MSG_CMDLINE_USAGE% + IDS_MSG_PARAM_PROCESSID %MSG_PARAM_PROCESSID% + IDS_MSG_PARAM_PROCESSID_DESCRIPTION %MSG_PARAM_PROCESSID_DESCRIPTION% + IDS_MSG_PARAM_HELP_DESCRIPTION %MSG_PARAM_HELP_DESCRIPTION% +END + +STRINGTABLE +BEGIN + IDS_OPTIONS_CAPTION %OPTIONS_TITLE% + IDS_PROXY_SETTINGS_HEADER %PROXY_SETTINGS_HEADER% + IDS_PROXY_SYSTEM %PROXY_SETTINGS_SYSTEM% + IDS_PROXY_DIRECT %PROXY_SETTINGS_DIRECT% + IDS_PROXY_MANUAL %PROXY_SETTINGS_MANUAL% + IDS_LABEL_PROXYSERVER %PROXY_SETTINGS_ADDRESS% + IDS_LABEL_PROXYPORT %PROXY_SETTINGS_PORT% + IDS_PROXY_DESCRIPTION %PROXY_SETTINGS_DESCRIPTION% +END diff --git a/crashrep/source/win32/resource.h b/crashrep/source/win32/resource.h new file mode 100755 index 000000000..75cee54ef --- /dev/null +++ b/crashrep/source/win32/resource.h @@ -0,0 +1,94 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by soreport.rc +// +#define IDD_DIALOG_FRAME 101 +#define IDS_WELCOME_CAPTION 102 +#define IDS_WELCOME_HEADER 103 +#define IDS_WELCOME_BODY1 104 +#define IDS_PRIVACY_URL 105 +#define IDS_NEXT_BUTTON 106 +#define IDD_WELCOME_PAGE 107 +#define IDS_CANCEL_BUTTON 107 +#define IDD_REPORT_PAGE 108 +#define IDS_REPORT_CAPTION 108 +#define IDS_REPORT_HEADER 109 +#define IDS_DESCRIPTION 110 +#define IDS_REPORT_INTRO 110 +#define IDS_ENTER_TITLE 111 +#define IDS_ALLOW_CONTACT 112 +#define IDS_ENTER_DESCRIPTION 113 +#define IDS_BACK_BUTTON 114 +#define IDS_SEND_BUTTON 115 +#define IDS_DONOT_SEND_BUTTON 116 +#define IDS_SHOW_REPORT_BUTTON 117 +#define IDS_SAVE_REPORT_BUTTON 118 +#define IDD_PREVIEW_FRAME 119 +#define IDS_ERROR_MSG_SIMPLE_MAPI 120 +#define IDS_ERROR_MSG_DISK_FULL 121 +#define IDS_OK_BUTTON 122 +#define IDS_OPTIONS_BUTTON 123 +#define IDS_LABEL_EMAIL 124 +#define IDD_OPTIONS_FRAME 125 +#define IDS_OPTIONS_CAPTION 126 +#define IDS_PROXY_SETTINGS_HEADER 127 +#define IDS_PROXY_SYSTEM 128 +#define IDS_PROXY_DIRECT 129 +#define IDS_PROXY_MANUAL 130 +#define IDS_LABEL_PROXYSERVER 131 +#define IDS_LABEL_PROXYPORT 132 +#define IDS_PROXY_DESCRIPTION 133 +#define IDS_ERROR_MSG_PROXY 134 +#define IDS_ERROR_MSG_NOCONNECT 135 +#define IDS_SENDING_REPORT_HEADER 136 +#define IDS_SENDING_REPORT_STATUS 137 +#define IDS_SENDING_REPORT_STATUS_FINISHED 138 +#define IDD_SENDING_STATUS 139 +#define IDS_WELCOME_BODY2 140 +#define IDS_WELCOME_BODY3 141 +#define IDS_ERROR_MSG_NOEMAILADDRESS 142 +#define IDS_MSG_CMDLINE_USAGE 143 +#define IDS_MSG_PARAM_PROCESSID 144 +#define IDS_MSG_PARAM_PROCESSID_DESCRIPTION 145 +#define IDS_MSG_PARAM_HELP_DESCRIPTION 146 +#define IDC_RICHEDIT_HEADER 1005 +#define IDC_RICHEDIT21 1006 +#define IDC_ALLOW_CONTACT 1007 +#define IDC_EDIT_TITLE 1008 +#define IDC_EDIT_DESCRIPTION 1009 +#define IDC_SHOW_REPORT 1010 +#define IDC_SAVE_REPORT 1011 +#define IDNEXT 1012 +#define IDBACK 1014 +#define IDC_REPORT_INTRO 1015 +#define IDC_ENTER_TITLE 1016 +#define IDFINISH 1016 +#define IDC_ENTER_DESCRIPTION 1017 +#define IDC_EDIT3 1018 +#define IDC_HEADER 1019 +#define IDC_STATICBK 1020 +#define IDC_EDIT_PREVIEW 1021 +#define IDC_EDIT_EMAIL 1022 +#define IDC_OPTIONS 1023 +#define IDC_PROXY_SETTINGS 1024 +#define IDC_RADIO_SYSTEM 1025 +#define IDC_RADIO_DIRECT 1026 +#define IDC_RADIO_MANUAL 1027 +#define IDC_LABEL_PROXYSERVER 1028 +#define IDC_LABEL_PROXYPORT 1029 +#define IDC_EDIT_PROXYSERVER 1030 +#define IDC_EDIT_PROXYPORT 1031 +#define IDC_LABEL_EMAIL 1032 +#define IDC_PROXY_DESCRIPTION 1033 +#define IDC_SENDING_REPORT_STATUS 1034 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 147 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1035 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/crashrep/source/win32/soreport.cpp b/crashrep/source/win32/soreport.cpp new file mode 100755 index 000000000..0840815eb --- /dev/null +++ b/crashrep/source/win32/soreport.cpp @@ -0,0 +1,2272 @@ +#define UNICODE +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <windowsx.h> + +#include <mapi.h> +#include <commctrl.h> +#include <commdlg.h> +#include <psapi.h> + +#include <shellapi.h> + +#define _UNICODE +#include <tchar.h> + +#define _RICHEDIT_VER 0x0200 +#include <richedit.h> + + +#if _RICHEDIT_VER >= 0x0200 +#define RICHEDIT TEXT("riched20.dll") +#else +#define RICHEDIT TEXT("riched32.dll") +#endif + +#include <systools/win32/uwinapi.h> + +#include <stdlib.h> +#include <stdio.h> +#include <io.h> +#include <fcntl.h> +#include <string> +#include <winsock.h> +#include <malloc.h> +#include <process.h> + +#if _MSC_VER < 1300 +#define COMEX "9" +#else +#define COMEX "8" +#endif + +#ifdef PRODUCT +#define _INPATH "wntmsci" COMEX ".pro" +#else +#define _INPATH "wntmsci" COMEX +#endif + +#include "resource.h" +#include "base64.h" + +#define FORMATBUFSIZE (8*1024) +#define MAX_TEXT_BUFFER (32*1024-1) +#define MAX_HOSTNAME (1024) + +#include <dbghelp.h> + +using namespace ::std; + + +string g_strDefaultLanguage; +string g_strProductKey; +FILE *g_fpStackFile = 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] = ""; + +#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 *_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( (intptr_t)hFile, 0 ); + + fp = _fdopen( fd, "w+b" ); + } + } + } + + return fp; +} + +//*************************************************************************** + +struct CrashReportParams +{ + BOOL fAllowContact; + TCHAR szEmail[1024]; + TCHAR szTitle[1024]; + TCHAR szComment[2048]; + ULONG uInternetConnection; + TCHAR szProxyServer[1024]; + TCHAR szProxyPort[50]; + + CrashReportParams(); + void WriteToRegistry(); + void ReadFromRegistry(); +}; + +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; + _tcscpy( szTitle, TEXT("") ); + _tcscpy( szComment, TEXT("") ); + _tcscpy( szEmail, TEXT("") ); + uInternetConnection = 0; + _tcscpy( szProxyServer, TEXT("") ); + _tcscpy( szProxyPort, TEXT("") ); +} + +//*************************************************************************** + +void CrashReportParams::ReadFromRegistry() +{ + RegReadValue( + HKEY_CURRENT_USER, + TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), + TEXT("HTTPProxyServer"), + szProxyServer, + sizeof(szProxyServer) ); + + DWORD dwProxyPort; + + if ( ERROR_SUCCESS == RegReadValue( + HKEY_CURRENT_USER, + TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), + TEXT("HTTPProxyPort"), + &dwProxyPort, + sizeof(dwProxyPort) ) ) + _stprintf( szProxyPort, TEXT("%d"), dwProxyPort ); + + RegReadValue( + HKEY_CURRENT_USER, + TEXT("SOFTWARE\\OpenOffice.org\\CrashReport"), + TEXT("ReturnAddress"), + szEmail, + sizeof(szEmail) ); + + 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, + szProxyServer, + sizeof(TCHAR) * (_tcslen( szProxyServer ) + 1) ); + + LPTSTR endptr = NULL; + DWORD dwProxyPort = _tcstoul( szProxyPort, &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, + szEmail, + sizeof(TCHAR) * (_tcslen( szEmail ) + 1) ); +} + +//*************************************************************************** + +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 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 szBuffer[256] = TEXT(""); + 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( '\\' ); + aDir.erase( pos + 1 ); + + return aDir; +} + +//*************************************************************************** + +string GetFileName( const string& rFilePath ) +{ + string aName = rFilePath; + size_t pos = aName.rfind( '\\' ); + + return aName.substr( pos + 1 ); +} + +//*************************************************************************** + +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] = ""; + CHAR szUserName[256] = ""; + TCHAR tszUserName[256] = TEXT(""); + DWORD dwUserNameSize = elementsof(tszUserName); + const char *pszUserType = getenv( "STAROFFICE_USERTYPE" ); + + GetUserName( tszUserName, &dwUserNameSize ); + + WideCharToMultiByte( CP_UTF8, 0, pParams->szTitle, -1, szTitle, sizeof(szTitle), NULL, NULL ); + WideCharToMultiByte( CP_UTF8, 0, g_szBuildId, -1, szBuildId, sizeof(szBuildId), NULL, NULL ); + WideCharToMultiByte( CP_UTF8, 0, pParams->szEmail, -1, szEmail, sizeof(szEmail), NULL, NULL ); + WideCharToMultiByte( CP_UTF8, 0, tszUserName, -1, szUserName, sizeof(szUserName), 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\" uid=\"%s\" usertype=\"%s\">\n" + "<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.0\" feedback=\"%s\" email=\"%s\">\n", + szUserName, + 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, + g_strDefaultLanguage.c_str(), + GetModuleDirectory( NULL ).c_str(), + g_dwExceptionCode, + g_strProductKey.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 ); + + 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 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->szTitle ); + aString.append( _T("\r\n\r\n") ); + aString.append( pParams->szComment ); + 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] = (int)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->szProxyServer ); + Edit_SetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), pParams->szProxyPort ); + + 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: + { + Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYSERVER), pParams->szProxyServer, elementsof(pParams->szProxyServer) ); + Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_PROXYPORT), pParams->szProxyPort, elementsof(pParams->szProxyPort) ); + 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 ); +} + +//*************************************************************************** + +BOOL CALLBACK ReportDialogProc( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM 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->szEmail ); + + UpdateReportDialogControls( hwndDlg ); + } + return TRUE; + case WM_SHOWWINDOW: + if ( (BOOL)wParam ) + { + HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwndDlg, GWL_HINSTANCE ); + 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 ); + + SetFocus( GetDlgItem(hwndDlg,IDC_EDIT_TITLE) ); + } + break; + case WM_COMMAND: + switch ( LOWORD(wParam) ) + { + case IDC_SHOW_REPORT: + { + 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), pParams->szTitle, elementsof(pParams->szTitle) ); + Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_DESCRIPTION), pParams->szComment, elementsof(pParams->szComment) ); + Edit_GetText( GetDlgItem(hwndDlg, IDC_EDIT_EMAIL), pParams->szEmail, elementsof(pParams->szEmail) ); + 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 ); + } + 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: + { + 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), pParams->szTitle, elementsof(pParams->szTitle) ); + Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_DESCRIPTION), pParams->szComment, elementsof(pParams->szComment) ); + Edit_GetText( GetDlgItem(hwndPages[1], IDC_EDIT_EMAIL), pParams->szEmail, elementsof(pParams->szEmail) ); + + if ( pParams->fAllowContact && !pParams->szEmail[0] ) + { + 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->szComment ); + 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; +} + + + +//*************************************************************************** + +static bool WriteStackFile( FILE *fout, 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 ) ) + { + 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, + pSymbol->Name, + frame.AddrPC.Offset - pSymbol->Address, + GetFileName( moduleInfo.LoadedImageName ).c_str(), + 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, + GetFileName( moduleInfo.LoadedImageName ).c_str(), + 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 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 ) ) + { + TCHAR szFileName[MAX_PATH]; + + if ( GetTempFileName( szTempPath, TEXT("DMP"), 0, szFileName ) ) + { + HANDLE hFile = CreateFile( szFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 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; + TCHAR **argv = __targv; + 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 // 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 ) + { + 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( iEqualSign + 1, -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() +{ + TCHAR szBuffer[256] = TEXT(""); + TCHAR szModuleName[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") ); + + if ( + GetPrivateProfileString( + TEXT("Bootstrap"), + TEXT("ProductKey"), + TEXT("OpenOffice.org"), + szBuffer, + elementsof(szBuffer), + szModuleName ) + ) + { + int needed = WideCharToMultiByte( CP_UTF8, 0, szBuffer, -1, NULL, 0, NULL, NULL ); + char *pszBufferA = (char *)alloca( needed ); + + WideCharToMultiByte( CP_UTF8, 0, szBuffer, -1, pszBufferA, needed, NULL, NULL ); + g_strProductKey = pszBufferA; + + TCHAR *pVersion = _tcschr( 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("Bootstrap"), + TEXT("buildid"), + TEXT("unknown"), + g_szBuildId, elementsof(g_szBuildId), + szModuleName ); + + g_strDefaultLanguage = get_script_string( "instdb.inf", "DefaultLanguage" ); + + if ( GetPrivateProfileString( + TEXT("ErrorReport"), + TEXT("Port"), + 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("Server"), + TEXT(""), + szReportServer, elementsof(szReportServer), + szModuleName + ) ) + { + bSuccess = 0 != WideCharToMultiByte( CP_ACP, 0, szReportServer, -1, g_szReportServerA, elementsof(g_szReportServerA), NULL, NULL ); + } + + 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.szProxyServer, -1, + szProxyServer, sizeof(szProxyServer), NULL, NULL ); + uProxyPort = (unsigned short)_tcstoul( rParams.szProxyPort, &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 ) + { + char szHTTPProxyServer[1024] = ""; + + lpHttpStart += 5; + TCHAR *lpHttpEnd = _tcschr( lpHttpStart, ';' ); + + if ( lpHttpEnd ) + *lpHttpEnd = 0; + WideCharToMultiByte( CP_ACP, 0, lpHttpStart, -1, szHTTPProxyServer, sizeof(szHTTPProxyServer), NULL, NULL ); + + char *lpColon = strchr( szHTTPProxyServer, ':' ); + + if ( lpColon ) + { + char *endptr = NULL; + + *lpColon = 0; + strcpy( szProxyServer, szHTTPProxyServer ); + uProxyPort = (unsigned short)strtoul( lpColon + 1, &endptr, 10 ); + } + else + { + strcpy( szProxyServer, szHTTPProxyServer ); + uProxyPort = 8080; + } + } + } + } + } + break; + default: + case 1: + break; + } + + FILE *fptemp = _tmpfile(); + if ( fptemp ) + { + WriteSOAPRequest( fptemp ); + fseek( fptemp, 0, SEEK_SET ); + + 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; + + 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 ); + } + } + + fclose( fptemp ); + } + else + { + TCHAR szMessage[1024]; + + LoadAndFormatString( GetModuleHandle(NULL), IDS_ERROR_MSG_DISK_FULL, szMessage, elementsof(szMessage) ); + + MessageBox( hwndParent, szMessage, NULL, MB_ICONERROR | MB_OK ); + } + + return success; +} + +//*************************************************************************** + +int WINAPI _tWinMain( HINSTANCE hInstance, HINSTANCE, LPTSTR lpCmdLine, int ) +{ + int exitcode = -1; + + + PEXCEPTION_POINTERS pExceptionPointers = NULL; + DWORD dwProcessId = 0; + DWORD dwThreadId = 0; + + WSADATA wsaData; + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(1, 1); + WSAStartup(wVersionRequested, &wsaData); + + if ( ReadBootstrapParams() && ParseCommandArgs( &dwProcessId, &pExceptionPointers, &dwThreadId ) && dwProcessId ) + { + if ( WriteDumpFile( dwProcessId, pExceptionPointers, dwThreadId ) ) + { + g_fpStackFile = _tmpfile(); + + WriteStackFile( g_fpStackFile, dwProcessId, pExceptionPointers ); + + InitCommonControls(); + + if ( InitRichEdit() ) + { + CrashReportParams Params; + + Params.ReadFromRegistry(); + + INT_PTR result = DialogBoxParam( hInstance, MAKEINTRESOURCE(IDD_DIALOG_FRAME), NULL, DialogProc, (LPARAM)&Params ); + + if ( result > 0 ) + { + exitcode = 0; + } + DeinitRichEdit(); + } + + if ( g_szReportFileNameA[0] ) + DeleteFileA( g_szReportFileNameA ); + + if ( g_szCommentFileNameA[0] ) + DeleteFileA( g_szCommentFileNameA ); + + DeleteFileA( g_szDumpFileNameA ); + + if ( g_fpStackFile ) + fclose( g_fpStackFile ); + } + } + + + return exitcode; +} + |