/* This file is part of the KDE project Copyright (C) 1999 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kbugreport.h" #include #include #include #include #include "kdepackages.h" #include #include #include #include #include class KBugReportPrivate { public: KComboBox *appcombo; TQString lastError; TQString kde_version; TQString appname; TQString os; TQPushButton *submitBugButton; KURL url; }; KBugReport::KBugReport( TQWidget * parentw, bool modal, const KAboutData *aboutData ) : KDialogBase( Plain, i18n("Submit Bug Report"), Ok | Cancel, Ok, parentw, "KBugReport", modal, // modal true // separator ) { d = new KBugReportPrivate; // Use supplied aboutdata, otherwise the one from the active instance // otherwise the KGlobal one. _activeInstance should neved be 0L in theory. m_aboutData = aboutData ? aboutData : ( KGlobal::_activeInstance ? KGlobal::_activeInstance->aboutData() : KGlobal::instance()->aboutData() ); m_process = 0; TQWidget * parent = plainPage(); d->submitBugButton = 0; //if ( m_aboutData->bugAddress() == TQString::tqfromLatin1("submit@bugs.pearsoncomputing.net") ) //{ // // This is a core KDE application -> redirect to the web form // Always redirect to the Web form for Trinity d->submitBugButton = new TQPushButton( parent ); setButtonCancel( KStdGuiItem::close() ); //} TQLabel * tmpLabel; TQVBoxLayout * lay = new TQVBoxLayout( parent, 0, spacingHint() ); TQGridLayout *glay = new TQGridLayout( lay, 4, 3 ); glay->setColStretch( 1, 10 ); glay->setColStretch( 2, 10 ); int row = 0; if ( !d->submitBugButton ) { // From TQString qwtstr = i18n( "Your email address. If incorrect, use the Configure Email button to change it" ); tmpLabel = new TQLabel( i18n("From:"), parent ); glay->addWidget( tmpLabel, row,0 ); TQWhatsThis::add( tmpLabel, qwtstr ); m_from = new TQLabel( parent ); glay->addWidget( m_from, row, 1 ); TQWhatsThis::add( m_from, qwtstr ); // Configure email button m_configureEmail = new TQPushButton( i18n("Configure Email..."), parent ); connect( m_configureEmail, TQT_SIGNAL( clicked() ), this, TQT_SLOT( slotConfigureEmail() ) ); glay->addMultiCellWidget( m_configureEmail, 0, 2, 2, 2, (TQ_Alignment)(AlignTop|AlignRight) ); // To qwtstr = i18n( "The email address this bug report is sent to." ); tmpLabel = new TQLabel( i18n("To:"), parent ); glay->addWidget( tmpLabel, ++row,0 ); TQWhatsThis::add( tmpLabel, qwtstr ); tmpLabel = new TQLabel( m_aboutData->bugAddress(), parent ); glay->addWidget( tmpLabel, row, 1 ); TQWhatsThis::add( tmpLabel, qwtstr ); setButtonOK( KGuiItem( i18n("&Send"), "mail_send", i18n( "Send bug report." ), i18n( "Send this bug report to %1." ).arg( m_aboutData->bugAddress() ) ) ); } else { m_configureEmail = 0; m_from = 0; showButtonOK( false ); } // Program name TQString qwtstr = i18n( "The application for which you wish to submit a bug report - if incorrect, please use the Report Bug menu item of the correct application" ); tmpLabel = new TQLabel( i18n("Application: "), parent ); glay->addWidget( tmpLabel, ++row, 0 ); TQWhatsThis::add( tmpLabel, qwtstr ); d->appcombo = new KComboBox( false, parent, "app"); TQWhatsThis::add( d->appcombo, qwtstr ); d->appcombo->insertStrList((const char**)packages); connect(d->appcombo, TQT_SIGNAL(activated(int)), TQT_SLOT(appChanged(int))); d->appname = TQString::tqfromLatin1( m_aboutData ? m_aboutData->productName() : tqApp->name() ); glay->addWidget( d->appcombo, row, 1 ); int index = 0; for (; index < d->appcombo->count(); index++) { if (d->appcombo->text(index) == d->appname) { break; } } if (index == d->appcombo->count()) { // not present d->appcombo->insertItem(d->appname); } d->appcombo->setCurrentItem(index); TQWhatsThis::add( tmpLabel, qwtstr ); // Version qwtstr = i18n( "The version of this application - please make sure that no newer version is available before sending a bug report" ); tmpLabel = new TQLabel( i18n("Version:"), parent ); glay->addWidget( tmpLabel, ++row, 0 ); TQWhatsThis::add( tmpLabel, qwtstr ); if (m_aboutData) m_strVersion = m_aboutData->version(); else m_strVersion = i18n("no version set (programmer error!)"); d->kde_version = TQString::tqfromLatin1( KDE_VERSION_STRING ); d->kde_version += ", " + TQString::tqfromLatin1( KDE_DISTRIBUTION_TEXT ); if ( !d->submitBugButton ) m_strVersion += " " + d->kde_version; m_version = new TQLabel( m_strVersion, parent ); //glay->addWidget( m_version, row, 1 ); glay->addMultiCellWidget( m_version, row, row, 1, 2 ); TQWhatsThis::add( m_version, qwtstr ); tmpLabel = new TQLabel(i18n("OS:"), parent); glay->addWidget( tmpLabel, ++row, 0 ); struct utsname unameBuf; uname( &unameBuf ); d->os = TQString::tqfromLatin1( unameBuf.sysname ) + " (" + TQString::tqfromLatin1( unameBuf.machine ) + ") " "release " + TQString::tqfromLatin1( unameBuf.release ); tmpLabel = new TQLabel(d->os, parent); glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 ); tmpLabel = new TQLabel(i18n("Compiler:"), parent); glay->addWidget( tmpLabel, ++row, 0 ); tmpLabel = new TQLabel(TQString::tqfromLatin1(KDE_COMPILER_VERSION), parent); glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 ); if ( !d->submitBugButton ) { // Severity m_bgSeverity = new TQHButtonGroup( i18n("Se&verity"), parent ); static const char * const sevNames[5] = { "critical", "grave", "normal", "wishlist", "i18n" }; const TQString sevTexts[5] = { i18n("Critical"), i18n("Grave"), i18n("normal severity","Normal"), i18n("Wishlist"), i18n("Translation") }; for (int i = 0 ; i < 5 ; i++ ) { // Store the severity string as the name TQRadioButton *rb = new TQRadioButton( sevTexts[i], m_bgSeverity, sevNames[i] ); if (i==2) rb->setChecked(true); // default : "normal" } lay->addWidget( m_bgSeverity ); // Subject TQHBoxLayout * hlay = new TQHBoxLayout( lay ); tmpLabel = new TQLabel( i18n("S&ubject: "), parent ); hlay->addWidget( tmpLabel ); m_subject = new KLineEdit( parent ); m_subject->setFocus(); tmpLabel->setBuddy(m_subject); hlay->addWidget( m_subject ); TQString text = i18n("Enter the text (in English if possible) that you wish to submit for the " "bug report.\n" "If you press \"Send\", a mail message will be sent to the maintainer of " "this program.\n"); TQLabel * label = new TQLabel( parent, "label" ); label->setText( text ); lay->addWidget( label ); // The multiline-edit m_lineedit = new TQMultiLineEdit( parent, "TQMultiLineEdit" ); m_lineedit->setMinimumHeight( 180 ); // make it big m_lineedit->setWordWrap(TQMultiLineEdit::WidgetWidth); lay->addWidget( m_lineedit, 10 /*stretch*/ ); slotSetFrom(); } else { // Point to the web form lay->addSpacing(10); TQString text = i18n("To submit a bug report, click on the button below.\n" "This will open a web browser window on http://bugs.pearsoncomputing.net where you will find a form to fill in.\n" "The information displayed above will be transferred to that server."); TQLabel * label = new TQLabel( text, parent, "label"); lay->addWidget( label ); lay->addSpacing(10); updateURL(); d->submitBugButton->setText( i18n("&Launch Bug Report Wizard") ); d->submitBugButton->tqsetSizePolicy(TQSizePolicy::Fixed,TQSizePolicy::Fixed); lay->addWidget( d->submitBugButton ); lay->addSpacing(10); connect( d->submitBugButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotOk())); } } KBugReport::~KBugReport() { delete d; } void KBugReport::updateURL() { KURL url ( "http://bugs.pearsoncomputing.net/enter_bug.cgi" ); url.addQueryItem( "product", "KDE 3.5" ); url.addQueryItem( "op_sys", d->os ); url.addQueryItem( "cf_kde_compiler", KDE_COMPILER_VERSION ); url.addQueryItem( "cf_kde_version", d->kde_version ); url.addQueryItem( "cf_kde_appversion", m_strVersion ); url.addQueryItem( "cf_kde_package", d->appcombo->currentText() ); url.addQueryItem( "cf_kde_kbugreport", "1" ); d->url = url; } void KBugReport::appChanged(int i) { TQString appName = d->appcombo->text(i); int index = appName.tqfind( '/' ); if ( index > 0 ) appName = appName.left( index ); kdDebug() << "appName " << appName << endl; if (d->appname == appName && m_aboutData) m_strVersion = m_aboutData->version(); else m_strVersion = i18n("unknown program name", "unknown"); if ( !d->submitBugButton ) m_strVersion += d->kde_version; m_version->setText(m_strVersion); if ( d->submitBugButton ) updateURL(); } void KBugReport::slotConfigureEmail() { if (m_process) return; m_process = new KProcess; *m_process << TQString::tqfromLatin1("kcmshell") << TQString::tqfromLatin1("kcm_useraccount"); connect(m_process, TQT_SIGNAL(processExited(KProcess *)), TQT_SLOT(slotSetFrom())); if (!m_process->start()) { kdDebug() << "Couldn't start kcmshell.." << endl; delete m_process; m_process = 0; return; } m_configureEmail->setEnabled(false); } void KBugReport::slotSetFrom() { delete m_process; m_process = 0; m_configureEmail->setEnabled(true); // ### KDE4: why oh why is KEmailSettings in kio? KConfig emailConf( TQString::tqfromLatin1("emaildefaults") ); // find out the default profile emailConf.setGroup( TQString::tqfromLatin1("Defaults") ); TQString profile = TQString::tqfromLatin1("PROFILE_"); profile += emailConf.readEntry( TQString::tqfromLatin1("Profile"), TQString::tqfromLatin1("Default") ); emailConf.setGroup( profile ); TQString fromaddr = emailConf.readEntry( TQString::tqfromLatin1("EmailAddress") ); if (fromaddr.isEmpty()) { struct passwd *p; p = getpwuid(getuid()); fromaddr = TQString::tqfromLatin1(p->pw_name); } else { TQString name = emailConf.readEntry( TQString::tqfromLatin1("FullName")); if (!name.isEmpty()) fromaddr = name + TQString::tqfromLatin1(" <") + fromaddr + TQString::tqfromLatin1(">"); } m_from->setText( fromaddr ); } void KBugReport::slotUrlClicked(const TQString &urlText) { if ( kapp ) kapp->invokeBrowser( urlText ); // When using the web form, a click can also close the window, as there's // not much to do. It also gives the user a direct response to his click: if ( d->submitBugButton ) KDialogBase::slotCancel(); } void KBugReport::slotOk( void ) { if ( d->submitBugButton ) { if ( kapp ) kapp->invokeBrowser( d->url.url() ); return; } if( m_lineedit->text().isEmpty() || m_subject->text().isEmpty() ) { TQString msg = i18n("You must specify both a subject and a description " "before the report can be sent."); KMessageBox::error(this,msg); return; } switch ( m_bgSeverity->id( m_bgSeverity->selected() ) ) { case 0: // critical if ( KMessageBox::questionYesNo( this, i18n( "

You chose the severity Critical. " "Please note that this severity is intended only for bugs that

" "
  • break unrelated software on the system (or the whole system)
  • " "
  • cause serious data loss
  • " "
  • introduce a security hole on the system where the affected package is installed
\n" "

Does the bug you are reporting cause any of the above damage? " "If it does not, please select a lower severity. Thank you!

" ),TQString::null,KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No ) return; break; case 1: // grave if ( KMessageBox::questionYesNo( this, i18n( "

You chose the severity Grave. " "Please note that this severity is intended only for bugs that

" "
  • make the package in question unusable or mostly so
  • " "
  • cause data loss
  • " "
  • introduce a security hole allowing access to the accounts of users who use the affected package
\n" "

Does the bug you are reporting cause any of the above damage? " "If it does not, please select a lower severity. Thank you!

" ),TQString::null,KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No ) return; break; } if( !sendBugReport() ) { TQString msg = i18n("Unable to send the bug report.\n" "Please submit a bug report manually...\n" "See http://bugs.pearsoncomputing.net/ for instructions."); KMessageBox::error(this, msg + "\n\n" + d->lastError); return; } KMessageBox::information(this, i18n("Bug report sent, thank you for your input.")); accept(); } void KBugReport::slotCancel() { if( !d->submitBugButton && ( m_lineedit->edited() || m_subject->edited() ) ) { int rc = KMessageBox::warningYesNo( this, i18n( "Close and discard\nedited message?" ), i18n( "Close Message" ), KStdGuiItem::discard(), KStdGuiItem::cont() ); if( rc == KMessageBox::No ) return; } KDialogBase::slotCancel(); } TQString KBugReport::text() const { kdDebug() << m_bgSeverity->selected()->name() << endl; // Prepend the pseudo-headers to the contents of the mail TQString severity = TQString::tqfromLatin1(m_bgSeverity->selected()->name()); TQString appname = d->appcombo->currentText(); TQString os = TQString::tqfromLatin1("OS: %1 (%2)\n"). arg(KDE_COMPILING_OS). arg(KDE_DISTRIBUTION_TEXT); TQString bodyText; for(int i = 0; i < m_lineedit->numLines(); i++) { TQString line = m_lineedit->textLine(i); if (!line.endsWith("\n")) line += '\n'; bodyText += line; } if (severity == TQString::tqfromLatin1("i18n") && KGlobal::locale()->language() != KLocale::defaultLanguage()) { // Case 1 : i18n bug TQString package = TQString::tqfromLatin1("i18n_%1").arg(KGlobal::locale()->language()); package = package.replace(TQString::tqfromLatin1("_"), TQString::tqfromLatin1("-")); return TQString::tqfromLatin1("Package: %1").arg(package) + TQString::tqfromLatin1("\n" "Application: %1\n" // not really i18n's version, so better here IMHO "Version: %2\n").arg(appname).arg(m_strVersion)+ os+TQString::tqfromLatin1("\n")+bodyText; } else { appname = appname.replace(TQString::tqfromLatin1("_"), TQString::tqfromLatin1("-")); // Case 2 : normal bug return TQString::tqfromLatin1("Package: %1\n" "Version: %2\n" "Severity: %3\n") .arg(appname).arg(m_strVersion).arg(severity)+ TQString::tqfromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+ os+TQString::tqfromLatin1("\n")+bodyText; } } bool KBugReport::sendBugReport() { TQString recipient ( m_aboutData ? m_aboutData->bugAddress() : TQString::tqfromLatin1("submit@bugs.pearsoncomputing.net") ); TQString command; command = locate("exe", "ksendbugmail"); if (command.isEmpty()) command = KStandardDirs::findExe( TQString::tqfromLatin1("ksendbugmail") ); KTempFile outputfile; outputfile.close(); TQString subject = m_subject->text(); command += " --subject "; command += KProcess::quote(subject); command += " --recipient "; command += KProcess::quote(recipient); command += " > "; command += KProcess::quote(outputfile.name()); fflush(stdin); fflush(stderr); FILE * fd = popen(TQFile::encodeName(command), "w"); if (!fd) { kdError() << "Unable to open a pipe to " << command << endl; return false; } TQString btext = text(); fwrite(btext.ascii(),btext.length(),1,fd); fflush(fd); int error = pclose(fd); kdDebug() << "exit status1 " << error << " " << (WIFEXITED(error)) << " " << WEXITSTATUS(error) << endl; if ((WIFEXITED(error)) && WEXITSTATUS(error) == 1) { TQFile of(outputfile.name()); if (of.open(IO_ReadOnly )) { TQTextStream is(&of); is.setEncoding(TQTextStream::UnicodeUTF8); TQString line; while (!is.eof()) line = is.readLine(); d->lastError = line; } else { d->lastError = TQString::null; } outputfile.unlink(); return false; } outputfile.unlink(); return true; } void KBugReport::virtual_hook( int id, void* data ) { KDialogBase::virtual_hook( id, data ); } #include "kbugreport.moc"