diff options
Diffstat (limited to 'crashrep/source/unx')
-rwxr-xr-x | crashrep/source/unx/interface.cxx | 718 | ||||
-rwxr-xr-x | crashrep/source/unx/interface.hxx | 192 | ||||
-rwxr-xr-x | crashrep/source/unx/main.cxx | 1125 | ||||
-rwxr-xr-x | crashrep/source/unx/makefile.mk | 81 | ||||
-rwxr-xr-x | crashrep/source/unx/res.cxx | 140 | ||||
-rwxr-xr-x | crashrep/source/unx/res/makefile.mk | 63 | ||||
-rwxr-xr-x | crashrep/source/unx/res/unxcrashres.cxx | 104 |
7 files changed, 2423 insertions, 0 deletions
diff --git a/crashrep/source/unx/interface.cxx b/crashrep/source/unx/interface.cxx new file mode 100755 index 000000000000..f9768ed4a5de --- /dev/null +++ b/crashrep/source/unx/interface.cxx @@ -0,0 +1,718 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: interface.cxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#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 ); + + XEvent event; + + memset( &event, 0, sizeof(event) ); + + event.xexpose.type = Expose; + event.xexpose.display = GDK_DISPLAY(); + event.xexpose.window = GDK_WINDOW_XWINDOW( m_pStatusDialog->window ); + event.xexpose.width = event.xexpose.height = 10; + + XSendEvent( + GDK_DISPLAY(), + GDK_WINDOW_XWINDOW( m_pStatusDialog->window ), + True, + ExposureMask, + &event ); + + XFlush( GDK_DISPLAY() ); + } +} + + +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 ); + + hash_map<string, string>::iterator aIter; + aIter = rSettings.find( "TITLE" ); + if( aIter != rSettings.end() ) + gtk_entry_set_text( GTK_ENTRY(m_pEdit), aIter->second.c_str() ); + + 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 ); + + aIter = rSettings.find( "DESCRIPTION" ); + if( aIter != rSettings.end() ) + { + GtkTextBuffer* pBuffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(m_pEntry) ); + gtk_text_buffer_set_text( pBuffer, aIter->second.c_str(), -1 ); + } + + + 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 ); + + 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 000000000000..ad80c218fa65 --- /dev/null +++ b/crashrep/source/unx/interface.hxx @@ -0,0 +1,192 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: interface.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include <X11/Xlib.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 *pDialog, 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 000000000000..ca24d508ae07 --- /dev/null +++ b/crashrep/source/unx/main.cxx @@ -0,0 +1,1125 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: main.cxx,v $ + * $Revision: 1.30 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <cstdio> +#include <stdlib.h> +#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> +#include <limits.h> + +#include <hash_map> +#include <vector> +#include <string> + +#if defined (LINUX) || (FREEBSD) +#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 bool g_bNoUI = false; +static bool g_bSendReport = false; +static bool g_bLoadReport = false; + +static bool g_bDebugMode = false; +static int g_signal = 0; + +static string g_strProductKey; +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_strChecksumFileName; +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" + +#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_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_report( const hash_map< string, string >& rSettings ) +{ + FILE *fp = fopen( tmpnam( g_szReportFile ), "w" ); + const char *pszUserType = getenv( "STAROFFICE_USERTYPE" ); + + fprintf( fp, + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<!DOCTYPE errormail:errormail PUBLIC \"-//OpenOffice.org//DTD ErrorMail 1.0//EN\" \"errormail.dtd\">\n" + "<errormail:errormail xmlns:errormail=\"http://openoffice.org/2002/errormail\" usertype=\"%s\">\n" + "<reportmail:mail xmlns:reportmail=\"http://openoffice.org/2002/reportmail\" version=\"1.1\" feedback=\"%s\" email=\"%s\">\n" + "<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" + , + pszUserType ? xml_encode( pszUserType ).c_str() : "", + 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() ? xml_encode( g_buildid ).c_str() : "unknown", + _INPATH, + g_strDefaultLanguage.c_str(), + g_signal, + g_strProductKey.length() ? xml_encode(g_strProductKey).c_str() : "unknown", + xml_encode(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" + , + xml_encode( info.sysname ).c_str(), + xml_encode( info.version ).c_str(), + xml_encode( info.release ).c_str(), + xml_encode( getlocale() ).c_str() + ); + fprintf( fp, "<systeminfo:CPU type=\"%s\"/>\n", xml_encode( info.machine ).c_str() ); + fprintf( fp, "</systeminfo:systeminfo>\n" ); + + FILE *fpxml = fopen( g_strXMLFileName.c_str(), "r" ); + if ( fpxml ) + { + fcopy( fp, fpxml ); + fclose( fpxml ); + } + + FILE *fpchk = fopen( g_strChecksumFileName.c_str(), "r" ); + if ( fpchk ) + { + fcopy( fp, fpchk ); + fclose( fpchk ); + } + + 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; +} + +#if 0 +// unused +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() ); + } +} +#endif + +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, + static_cast<int>(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", + static_cast<int>(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\">stack.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; +}; + + +bool send_crash_report( const hash_map< string, string >& rSettings ) +{ + if ( 0 == strcasecmp( rSettings.find( "CONTACT" )->second.c_str(), "true" ) && + !trim_string(rSettings.find( "EMAIL" )->second).length() ) + { + 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 + ); + + fclose( fptemp ); + + } + + 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; + + 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 ) +{ + char szCanonicProgPath[PATH_MAX]; + + + if ( realpath( progname, szCanonicProgPath ) ) + { + string aDir = szCanonicProgPath; + + 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 ( 0 == strcmp( argv[n], "-chksum" ) ) + { + if ( ++n < argc ) + g_strChecksumFileName = argv[n]; + } + else if ( 0 == strcmp( argv[n], "-noui" ) ) + { + g_bNoUI = true; + } + else if ( 0 == strcmp( argv[n], "-send" ) ) + { + g_bSendReport = true; + } + else if ( 0 == strcmp( argv[n], "-load" ) ) + { + g_bLoadReport = true; + } + else if ( argv[n] && strlen(argv[n]) ) + { + printf( + "\n%s crash_report %s\n\n" \ + "/?, -h[elp] %s\n\n" \ + "%-20s %s\n\n", + "%MSG_CMDLINE_USAGE%", + "%MSG_PARAM_PROCESSID%", + "%MSG_PARAM_HELP_DESCRIPTION%", + "%MSG_PARAM_PROCESSID%", + "%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, string::npos ); + 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, string::npos ); + value = trim_string( value ); + + if ( + 0 == strcasecmp( section.c_str(), pSectionName ) && + 0 == strcasecmp( keyname.c_str(), pKeyName ) + ) + { + retValue = value; + break; + } + } + } + } + + fclose( fp ); + } + + return retValue; +} + +static string get_environment_string( const char *pEnvName ) +{ + const char *pEnvValue = getenv( pEnvName ); + + if ( pEnvValue ) + return pEnvValue; + else + return ""; +} + +static string read_from_file( const string& rFileName ) +{ + string content; + FILE *fp = fopen( rFileName.c_str(), "r" ); + + if ( fp ) + { + char buffer[256 + 1]; + size_t nBytesRead; + + while( 0 != ( nBytesRead = fread( buffer, 1, sizeof(buffer) - 1, fp ) ) ) + { + buffer[nBytesRead] = 0; + content += buffer; + } + + fclose( fp ); + } + + return content; +} + +#define RCFILE ".crash_reportrc" +#define XMLFILE ".crash_report_frames" +#define CHKFILE ".crash_report_checksum" +#define LCKFILE ".crash_report_unsent" +#define PRVFILE ".crash_report_preview" + +static void load_crash_data() +{ + g_strXMLFileName = get_home_dir(); + g_strXMLFileName += "/"; + g_strXMLFileName += string(XMLFILE); + + g_strChecksumFileName = get_home_dir(); + g_strChecksumFileName += "/"; + g_strChecksumFileName += string(CHKFILE); +} + +static bool write_crash_data() +{ + bool success = true; + string sFile = get_home_dir(); + + sFile += "/"; + sFile += string(XMLFILE); + + FILE *fp = fopen( sFile.c_str(), "w" ); + + if ( fp ) + { + FILE *fpin = fopen( g_strXMLFileName.c_str(), "r" ); + + if ( fpin ) + { + fcopy( fp, fpin ); + fclose( fpin ); + } + + fclose( fp ); + } + + sFile = get_home_dir(); + + sFile += "/"; + sFile += string(CHKFILE); + + fp = fopen( sFile.c_str(), "w" ); + + if ( fp ) + { + FILE *fpin = fopen( g_strChecksumFileName.c_str(), "r" ); + + if ( fpin ) + { + fcopy( fp, fpin ); + fclose( fpin ); + } + + fclose( fp ); + } + + sFile = get_home_dir(); + + sFile += "/"; + sFile += string(LCKFILE); + + fp = fopen( sFile.c_str(), "w" ); + + if ( fp ) + { + fprintf( fp, "Unsent\n" ); + fclose( fp ); + } + + return success; +} + +#if 0 +// unused +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; +} +#endif + +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" ); + rSettings[ "DESCRIPTION" ] = ""; + rSettings[ "TITLE" ] = ""; +} + +static void read_settings_from_environment( hash_map< string, string >& rSettings ) +{ + string strEnv; + + strEnv = get_environment_string( "ERRORREPORT_RETURNADDRESS" ); + if ( strEnv.length() ) + { + rSettings[ "EMAIL" ] = strEnv; + if ( !(rSettings.find( "CONTACT" )->second).length() ) + rSettings[ "CONTACT" ] = "true"; + } + else if ( !(rSettings.find( "CONTACT" )->second).length() ) + rSettings[ "CONTACT" ] = "false"; + + + strEnv = get_environment_string( "ERRORREPORT_HTTPPROXYSERVER" ); + if ( strEnv.length() ) + rSettings[ "SERVER" ] = strEnv; + + strEnv = get_environment_string( "ERRORREPORT_HTTPPROXYPORT" ); + if ( strEnv.length() ) + rSettings[ "PORT" ] = strEnv; + + strEnv = get_environment_string( "ERRORREPORT_HTTPCONNECTIONTYPE" ); + if ( strEnv.length() ) + rSettings[ "USEPROXY" ] = 0 == strcasecmp( strEnv.c_str(), "MANUALPROXY" ) ? "true" : "false"; + + strEnv = get_environment_string( "ERRORREPORT_BODYFILE" ); + if ( strEnv.length() ) + rSettings[ "DESCRIPTION" ] = read_from_file( strEnv ); + + strEnv = get_environment_string( "ERRORREPORT_SUBJECT" ); + if ( strEnv.length() ) + rSettings[ "TITLE" ] = strEnv; +} + +static bool setup_version() +{ + if ( !getenv( "PRODUCTNAME" ) ) + { + string productkey = get_profile_string( "bootstraprc", "Bootstrap", "ProductKey" ); + + g_strProductKey = 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, string::npos ); + } + 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( "versionrc", "Version", "BuildId" ); + g_strDefaultLanguage = get_script_string( "instdb.ins", "DefaultLanguage" ); + + g_strReportServer = get_profile_string( "bootstraprc", "ErrorReport", "ErrorReportServer" ); + + string strReportPort = get_profile_string( "bootstraprc", "ErrorReport", "ErrorReportPort", "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(); +} + +#if 0 +// Use gconftool-2 to determine if gnome accessiblity is enabled +// unused +static bool get_accessibility_state() +{ + bool bAccessible = false; + FILE *fin = popen( "gconftool-2 -g /desktop/gnome/interface/accessibility", "r"); + + if ( fin ) + { + char buffer[sizeof("true")]; + + bAccessible = fgets( buffer, sizeof(buffer), fin ) && 0 == strcmp( buffer, "true" ); + + pclose( fin ); + } + + return bAccessible; +} +#endif + +int main( int argc, char** argv ) +{ + freopen( "/dev/null", "w", stderr ); + + setup_program_dir( argv[0] ); + + // Don't start if accessiblity is enabled or report server is not given + + if ( setup_version() ) + { + /*long pid =*/ setup_commandline_arguments( argc, argv, &g_signal ); + + if ( g_bLoadReport ) + { + load_crash_data(); + } + + if ( g_bSendReport ) + { + hash_map< string, string > aDialogSettings; + + read_settings( aDialogSettings ); + read_settings_from_environment( aDialogSettings ); + + send_crash_report( aDialogSettings ); + } + else + { + hash_map< string, string > aDialogSettings; + + read_settings( aDialogSettings ); + read_settings_from_environment( aDialogSettings ); + + write_crash_data(); + write_report( aDialogSettings ); + + string sPreviewFile = get_home_dir(); + sPreviewFile += "/"; + sPreviewFile += string(PRVFILE); + + FILE *fpout = fopen( sPreviewFile.c_str(), "w+" ); + if ( fpout ) + { + FILE *fpin = fopen( g_szReportFile, "r" ); + if ( fpin ) + { + fcopy( fpout, fpin ); + fclose( fpin ); + } + fclose( fpout ); + } + + unlink( g_szReportFile ); + } + + if ( g_bLoadReport ) + { + unlink( g_strXMLFileName.c_str() ); + unlink( g_strChecksumFileName.c_str() ); + } + + 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 000000000000..2f8be8f96a76 --- /dev/null +++ b/crashrep/source/unx/makefile.mk @@ -0,0 +1,81 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.19 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=crashrep +TARGET=crash_report.bin +TARGETTYPE=CUI + +ENABLE_EXCEPTIONS=TRUE +LIBTARGET=NO +LIBSALCPPRT=$(0) + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# ------------------------------------------------------------------ + +# Only build crash reporter if either a product build with debug info +# or a non-pro build is done. + +.IF "$(ENABLE_CRASHDUMP)" != "" || "$(PRODUCT)" == "" + +SOLARLIB!:=$(SOLARLIB:s/jre/jnore/) + +OBJFILES=\ + $(OBJ)$/main.obj + +APP1NOSAL=TRUE +APP1TARGET=$(TARGET) +APP1OBJS=$(OBJFILES) +APP1RPATH=BRAND + +.IF "$(OS)" != "MACOSX" +APP1STDLIBS=$(DYNAMIC) -lXext -lX11 +.ENDIF +.IF "$(OS)" != "FREEBSD" && "$(OS)" != "MACOSX" && "$(OS)"!="NETBSD" +APP1STDLIBS+=-ldl -lnsl +.ENDIF +.IF "$(OS)" == "SOLARIS" +APP1STDLIBS+=-lsocket +.ENDIF + +.ENDIF # "$(ENABLE_CRASHDUMP)" != "" || "$(PRODUCT)" == "" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +$(OBJ)$/main.obj: $(INCCOM)$/_version.h + +# Building crash_report diff --git a/crashrep/source/unx/res.cxx b/crashrep/source/unx/res.cxx new file mode 100755 index 000000000000..63910d606a09 --- /dev/null +++ b/crashrep/source/unx/res.cxx @@ -0,0 +1,140 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: res.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#if OSL_DEBUG_LEVEL == 0 +# ifndef NDEBUG +# define NDEBUG +# endif +#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 000000000000..4e6d733e2d37 --- /dev/null +++ b/crashrep/source/unx/res/makefile.mk @@ -0,0 +1,63 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.6 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org 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 version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=crashrep +TARGET=unxcrashres +LIBTARGET=NO +TARGETTYPE=CUI + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(OS)"=="MACOSX" + +dummy: + @echo "Nothing to build for OS $(OS)" + +.ELSE # "$(OS)"=="MACOSX" + +# --- Files -------------------------------------------------------- + +SOLARLIB!:=$(SOLARLIB:s/jre/jnore/) + +APP1TARGET=$(TARGET) +APP1OBJS=$(OBJ)$/unxcrashres.obj +APP1STDLIBS=$(TOOLSLIB) $(SALLIB) + +.ENDIF "$(OS)"=="MACOSX" + +# --- 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 000000000000..4bfd34f58ba0 --- /dev/null +++ b/crashrep/source/unx/res/unxcrashres.cxx @@ -0,0 +1,104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unxcrashres.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/#include <tools/config.hxx> +#include <rtl/string.hxx> +#include <osl/thread.h> + +#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< ByteString, hash_map< OString, OString, OStringHash >, 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 ); + // tailor key + filterValue( aValue, aGroup, aKey ); + + aFiles[aKey][aGroup] = ByteString( aValue ); + } + } + + for( hash_map< ByteString, hash_map< OString, OString, OStringHash >, OStringHash >::const_iterator lang_it = aFiles.begin(); lang_it != aFiles.end(); ++lang_it ) + { + ByteString aFile( argv[2] ); + aFile.Append( '.' ); + aFile.Append( 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; +} |