kbugreport.cpp Source File (kdeui Library)

| # kdeui Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kbugreport.cpp

    00001 /* This file is part of the KDE project
    00002    Copyright (C) 1999 David Faure <faure@kde.org>
    00003
    00004    This library is free software; you can redistribute it and/or
    00005    modify it under the terms of the GNU Library General Public
    00006    License as published by the Free Software Foundation; either
    00007    version 2 of the License, or (at your option) any later version.
    00008
    00009    This library is distributed in the hope that it will be useful,
    00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012    Library General Public License for more details.
    00013
    00014    You should have received a copy of the GNU Library General Public License
    00015    along with this library; see the file COPYING.LIB.  If not, write to
    00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020 #include <qhbuttongroup.h>
    00021 #include <qpushbutton.h>
    00022 #include <qlabel.h>
    00023 #include <qlayout.h>
    00024 #include <qmultilineedit.h>
    00025 #include <qradiobutton.h>
    00026 #include <qwhatsthis.h>
    00027 #include <qregexp.h>
    00028
    00029 #include <kapplication.h>
    00030 #include <kaboutdata.h>
    00031 #include <kconfig.h>
    00032 #include <kstandarddirs.h>
    00033 #include <klineedit.h>
    00034 #include <klocale.h>
    00035 #include <kurl.h>
    00036 #include <kmessagebox.h>
    00037 #include <kdebug.h>
    00038 #include <kprocess.h>
    00039 #include <kurllabel.h>
    00040
    00041 #include "kbugreport.h"
    00042
    00043 #include <stdio.h>
    00044 #include <pwd.h>
    00045 #include <unistd.h>
    00046
    00047 #include <sys/utsname.h>
    00048
    00049 #include "kdepackages.h"
    00050 #include <kcombobox.h>
    00051 #include <config.h>
    00052 #include <ktempfile.h>
    00053 #include <qtextstream.h>
    00054 #include <qfile.h>
    00055
    00056 class KBugReportPrivate {
    00057 public:
    00058     KComboBox *appcombo;
    00059     QString lastError;
    00060     QString kde_version;
    00061     QString appname;
    00062     QString os;
    00063     KURLLabel *webFormLabel;
    00064 };
    00065
    00066 KBugReport::KBugReport( QWidget * parentw, bool modal, const KAboutData *aboutData )
    00067   : KDialogBase( Plain,
    00068                  i18n("Submit Bug Report"),
    00069                  Ok | Cancel,
    00070                  Ok,
    00071                  parentw,
    00072                  "KBugReport",
    00073                  modal, // modal
    00074                  true // separator
    00075                  )
    00076 {
    00077   d = new KBugReportPrivate;
    00078
    00079   // Use supplied aboutdata, otherwise the one from the active instance
    00080   // otherwise the KGlobal one. _activeInstance should neved be 0L in theory.
    00081   m_aboutData = aboutData
    00082     ? aboutData
    00083     : ( KGlobal::_activeInstance ? KGlobal::_activeInstance->aboutData()
    00084                                  : KGlobal::instance()->aboutData() );
    00085   m_process = 0;
    00086   QWidget * parent = plainPage();
    00087   d->webFormLabel = 0;
    00088
    00089   if ( m_aboutData->bugAddress() == QString::fromLatin1("submit@bugs.kde.org") )
    00090   {
    00091     // This is a core KDE application -> redirect to the web form
    00092     d->webFormLabel = new KURLLabel( parent );
    00093     setButtonCancelText(i18n("&Close"));
    00094   }
    00095
    00096   QLabel * tmpLabel;
    00097   QVBoxLayout * lay = new QVBoxLayout( parent, 0, spacingHint() );
    00098
    00099   QGridLayout *glay = new QGridLayout( lay, 4, 3 );
    00100   glay->setColStretch( 1, 10 );
    00101   glay->setColStretch( 2, 10 );
    00102
    00103   int row = 0;
    00104
    00105   if ( !d->webFormLabel )
    00106   {
    00107     // From
    00108     QString qwtstr = i18n( "Your email address. If incorrect, use the Configure Email button to change it" );
    00109     tmpLabel = new QLabel( i18n("From:"), parent );
    00110     glay->addWidget( tmpLabel, row,0 );
    00111     QWhatsThis::add( tmpLabel, qwtstr );
    00112     m_from = new QLabel( parent );
    00113     glay->addWidget( m_from, row, 1 );
    00114     QWhatsThis::add( m_from, qwtstr );
    00115
    00116
    00117     // Configure email button
    00118     m_configureEmail = new QPushButton( i18n("Configure Email..."),
    00119                                         parent );
    00120     connect( m_configureEmail, SIGNAL( clicked() ), this,
    00121              SLOT( slotConfigureEmail() ) );
    00122     glay->addMultiCellWidget( m_configureEmail, 0, 2, 2, 2, AlignTop|AlignRight );
    00123
    00124     // To
    00125     qwtstr = i18n( "The email address this bug report is sent to." );
    00126     tmpLabel = new QLabel( i18n("To:"), parent );
    00127     glay->addWidget( tmpLabel, ++row,0 );
    00128     QWhatsThis::add( tmpLabel, qwtstr );
    00129     tmpLabel = new QLabel( m_aboutData->bugAddress(), parent );
    00130     glay->addWidget( tmpLabel, row, 1 );
    00131     QWhatsThis::add( tmpLabel, qwtstr );
    00132
    00133     setButtonOKText(i18n("&Send"),
    00134                     i18n("Send bug report."),
    00135                     i18n("Send this bug report to the KDE buglist."));
    00136
    00137   }
    00138   else
    00139   {
    00140     m_configureEmail = 0;
    00141     m_from = 0;
    00142     showButtonOK( false );
    00143   }
    00144
    00145   // Program name
    00146   QString 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" );
    00147   tmpLabel = new QLabel( i18n("Application: "), parent );
    00148   glay->addWidget( tmpLabel, ++row, 0 );
    00149   QWhatsThis::add( tmpLabel, qwtstr );
    00150   d->appcombo = new KComboBox( false, parent, "app");
    00151   QWhatsThis::add( d->appcombo, qwtstr );
    00152   d->appcombo->insertStrList((const char**)packages);
    00153   connect(d->appcombo, SIGNAL(activated(int)), SLOT(appChanged(int)));
    00154   d->appname = QString::fromLatin1( m_aboutData
    00155                                     ? m_aboutData->appName()
    00156                                     : qApp->name() );
    00157   glay->addWidget( d->appcombo, row, 1 );
    00158   int index = 0;
    00159   for (; index < d->appcombo->count(); index++) {
    00160       if (d->appcombo->text(index) == d->appname) {
    00161           break;
    00162       }
    00163   }
    00164   if (index == d->appcombo->count()) { // not present
    00165       d->appcombo->insertItem(d->appname);
    00166   }
    00167   d->appcombo->setCurrentItem(index);
    00168
    00169   QWhatsThis::add( tmpLabel, qwtstr );
    00170
    00171   // Version
    00172   qwtstr = i18n( "The version of this application - please make sure that no newer version is available before sending a bug report" );
    00173   tmpLabel = new QLabel( i18n("Version:"), parent );
    00174   glay->addWidget( tmpLabel, ++row, 0 );
    00175   QWhatsThis::add( tmpLabel, qwtstr );
    00176   if (m_aboutData)
    00177       m_strVersion = m_aboutData->version();
    00178   else
    00179       m_strVersion = i18n("no version set (programmer error!)");
    00180   d->kde_version = QString::fromLatin1(" (KDE " KDE_VERSION_STRING ") ("
    00181           KDE_DISTRIBUTION_TEXT ")");
    00182   m_strVersion += d->kde_version;
    00183   m_version = new QLabel( m_strVersion, parent );
    00184   //glay->addWidget( m_version, row, 1 );
    00185   glay->addMultiCellWidget( m_version, row, row, 1, 2 );
    00186   QWhatsThis::add( m_version, qwtstr );
    00187
    00188   tmpLabel = new QLabel(i18n("OS:"), parent);
    00189   glay->addWidget( tmpLabel, ++row, 0 );
    00190
    00191   struct utsname unameBuf;
    00192   uname( &unameBuf );
    00193   d->os = QString::fromLatin1( unameBuf.sysname ) +
    00194                                         " (" + QString::fromLatin1( unameBuf.machine ) + ") "
    00195           "release " + QString::fromLatin1( unameBuf.release );
    00196
    00197   tmpLabel = new QLabel(d->os, parent);
    00198   glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 );
    00199
    00200   tmpLabel = new QLabel(i18n("Compiler:"), parent);
    00201   glay->addWidget( tmpLabel, ++row, 0 );
    00202   tmpLabel = new QLabel(QString::fromLatin1(KDE_COMPILER_VERSION), parent);
    00203   glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 );
    00204
    00205   if ( !d->webFormLabel )
    00206   {
    00207     // Severity
    00208     m_bgSeverity = new QHButtonGroup( i18n("Se&verity"), parent );
    00209     static const char * const sevNames[5] = { "critical", "grave", "normal", "wishlist", "i18n" };
    00210     const QString sevTexts[5] = { i18n("Critical"), i18n("Grave"), i18n("normal severity","Normal"), i18n("Wishlist"), i18n("Translation") };
    00211
    00212     for (int i = 0 ; i < 5 ; i++ )
    00213     {
    00214       // Store the severity string as the name
    00215       QRadioButton *rb = new QRadioButton( sevTexts[i], m_bgSeverity, sevNames[i] );
    00216       if (i==2) rb->setChecked(true); // default : "normal"
    00217     }
    00218
    00219     lay->addWidget( m_bgSeverity );
    00220
    00221     // Subject
    00222     QHBoxLayout * hlay = new QHBoxLayout( lay );
    00223     tmpLabel = new QLabel( i18n("S&ubject: "), parent );
    00224     hlay->addWidget( tmpLabel );
    00225     m_subject = new KLineEdit( parent );
    00226     m_subject->setFocus();
    00227     tmpLabel->setBuddy(m_subject);
    00228     hlay->addWidget( m_subject );
    00229
    00230     QString text = i18n(""
    00231                         "Enter the text (in English if possible) that you wish to submit for the "
    00232                         "bug report.\n"
    00233                         "If you press \"Send\", a mail message will be sent to the maintainer of "
    00234                         "this program \n"
    00235                         "and to the KDE buglist.");
    00236     QLabel * label = new QLabel( parent, "label" );
    00237
    00238     /*
    00239       2000-01-15 Espen
    00240       Does not work (yet). The label has no well defined height so the
    00241       dialog can be resized so that the action buttons become obscured
    00242
    00243       QString text = i18n(""
    00244       "Enter the text (in English if possible) that you wish to submit for the "
    00245       "bug report. If you press \"Send\", a mail message will be sent to the "
    00246       "maintainer of this program and to the KDE buglist.");
    00247       QLabel * label = new QLabel( parent, "label" );
    00248       label->setTextFormat( RichText );
    00249     */
    00250
    00251     label->setText( text );
    00252     lay->addWidget( label );
    00253
    00254     // The multiline-edit
    00255     m_lineedit = new QMultiLineEdit( parent, "QMultiLineEdit" );
    00256     m_lineedit->setMinimumHeight( 180 ); // make it big
    00257     m_lineedit->setWordWrap(QMultiLineEdit::WidgetWidth);
    00258     lay->addWidget( m_lineedit, 10 /*stretch*/ );
    00259
    00260     slotSetFrom();
    00261   } else {
    00262     // Point to the web form
    00263
    00264     lay->addSpacing(20);
    00265     QString text = i18n("To submit a bug report, click on the link below.\n"
    00266                         "This will open a web browser window on http://bugs.kde.org where you'll find a form to fill in.\n"
    00267                         "The information displayed above will be transferred to that server.");
    00268     QLabel * label = new QLabel( text, parent, "label");
    00269     lay->addWidget( label );
    00270     lay->addSpacing(20);
    00271
    00272     updateURL();
    00273     d->webFormLabel->setText( "http://bugs.kde.org/wizard/index.php" );
    00274     lay->addWidget( d->webFormLabel );
    00275     lay->addSpacing(20);
    00276
    00277     connect( d->webFormLabel, SIGNAL(leftClickedURL(const QString &)),
    00278              this, SLOT(slotUrlClicked(const QString &)));
    00279   }
    00280 }
    00281
    00282 KBugReport::~KBugReport()
    00283 {
    00284     delete d;
    00285 }
    00286
    00287 void KBugReport::updateURL()
    00288 {
    00289     QString url = QString::fromLatin1("http://bugs.kde.org/wizard/index.php");
    00290     url += "?os=";
    00291     url += KURL::encode_string( d->os );
    00292     url += "&compiler=";
    00293     url += KURL::encode_string( QString::fromLatin1(KDE_COMPILER_VERSION) );
    00294     url += "&version=";
    00295     url += KURL::encode_string( m_strVersion );
    00296     url += "&package=";
    00297     url += KURL::encode_string( d->appcombo->currentText() );
    00298     url += "&kbugreport=1";
    00299     d->webFormLabel->setURL( url );
    00300 }
    00301
    00302 void KBugReport::appChanged(int i)
    00303 {
    00304     if (d->appname == d->appcombo->text(i) && m_aboutData)
    00305         m_strVersion = m_aboutData->version();
    00306     else
    00307         m_strVersion = i18n("unknown program name", "unknown");
    00308
    00309     m_strVersion += d->kde_version;
    00310     m_version->setText(m_strVersion);
    00311     if ( d->webFormLabel )
    00312         updateURL();
    00313 }
    00314
    00315 void KBugReport::slotConfigureEmail()
    00316 {
    00317   if (m_process) return;
    00318   m_process = new KProcess;
    00319   *m_process << QString::fromLatin1("kcmshell") << QString::fromLatin1("email");
    00320   connect(m_process, SIGNAL(processExited(KProcess *)), SLOT(slotSetFrom()));
    00321   if (!m_process->start())
    00322   {
    00323     kdDebug() << "Couldn't start kcmshell.." << endl;
    00324     delete m_process;
    00325     m_process = 0;
    00326     return;
    00327   }
    00328   m_configureEmail->setEnabled(false);
    00329 }
    00330
    00331 void KBugReport::slotSetFrom()
    00332 {
    00333   delete m_process;
    00334   m_process = 0;
    00335   m_configureEmail->setEnabled(true);
    00336
    00337   // ### KDE3: why oh why is KEmailSettings in kio?
    00338   KConfig emailConf( QString::fromLatin1("emaildefaults") );
    00339
    00340   // find out the default profile
    00341   emailConf.setGroup( QString::fromLatin1("Defaults") );
    00342   QString profile = QString::fromLatin1("PROFILE_");
    00343   profile += emailConf.readEntry( QString::fromLatin1("Profile"),
    00344                                   QString::fromLatin1("Default") );
    00345
    00346   emailConf.setGroup( profile );
    00347   QString fromaddr = emailConf.readEntry( QString::fromLatin1("EmailAddress") );
    00348   if (fromaddr.isEmpty()) {
    00349      struct passwd *p;
    00350      p = getpwuid(getuid());
    00351      fromaddr = QString::fromLatin1(p->pw_name);
    00352   } else {
    00353      QString name = emailConf.readEntry( QString::fromLatin1("FullName"));
    00354      if (!name.isEmpty())
    00355         fromaddr = name + QString::fromLatin1(" <") + fromaddr + QString::fromLatin1(">");
    00356   }
    00357   m_from->setText( fromaddr );
    00358 }
    00359
    00360 void KBugReport::slotUrlClicked(const QString &urlText)
    00361 {
    00362   if ( kapp )
    00363     kapp->invokeBrowser( urlText );
    00364
    00365   // When using the web form, a click can also close the window, as there's
    00366   // not much to do. It also gives the user a direct response to his click:
    00367   if ( d->webFormLabel )
    00368       KDialogBase::slotCancel();
    00369 }
    00370
    00371
    00372 void KBugReport::slotOk( void )
    00373 {
    00374     if ( d->webFormLabel)
    00375         return;
    00376
    00377     if( m_lineedit->text().isEmpty() == true ||
    00378         m_subject->text().isEmpty() == true )
    00379     {
    00380         QString msg = i18n("You must specify both a subject and a description "
    00381                            "before the report can be sent.");
    00382         KMessageBox::error(this,msg);
    00383         return;
    00384     }
    00385
    00386     switch ( m_bgSeverity->id( m_bgSeverity->selected() ) )
    00387     {
    00388         case 0: // critical
    00389             if ( KMessageBox::questionYesNo( this, i18n(
    00390                 "<p>You chose the severity <b>Critical</b>. "
    00391                 "Please note that this severity is intended only for bugs that</p>"
    00392                 "<ul><li>break unrelated software on the system (or the whole system)</li>"
    00393                 "<li>cause serious data loss</li>"
    00394                 "<li>introduce a security hole on the system where the affected package is installed</li></ul>\n"
    00395                 "<p>Does the bug you are reporting cause any of the above damage? "
    00396                 "If it does not, please select a lower severity. Thank you!</p>" ) ) == KMessageBox::No )
    00397                 return;
    00398             break;
    00399         case 1: // grave
    00400             if ( KMessageBox::questionYesNo( this, i18n(
    00401                 "<p>You chose the severity <b>Grave</b>. "
    00402                 "Please note that this severity is intended only for bugs that</p>"
    00403                 "<ul><li>make the package in question unusable or mostly so</li>"
    00404                 "<li>cause data loss</li>"
    00405                 "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n"
    00406                 "<p>Does the bug you are reporting cause any of the above damage? "
    00407                 "If it does not, please select a lower severity. Thank you!</p>" ) ) == KMessageBox::No )
    00408                 return;
    00409             break;
    00410     }
    00411     if( !sendBugReport() )
    00412     {
    00413         QString msg = i18n(""
    00414                            "Unable to send the bug report.\n"
    00415                            "Please submit a bug report manually...\n"
    00416                            "See http://bugs.kde.org/ for instructions.");
    00417         KMessageBox::error(this, msg + "\n\n" + d->lastError);
    00418         return;
    00419     }
    00420
    00421     KMessageBox::information(this,
    00422                              i18n("Bug report sent, thank you for your input."));
    00423     accept();
    00424 }
    00425
    00426 void KBugReport::slotCancel()
    00427 {
    00428   if( !d->webFormLabel && ( m_lineedit->edited() || m_subject->edited() ) )
    00429   {
    00430     int rc = KMessageBox::warningYesNo( this,
    00431              i18n( "Close and discard\nedited message?" ),
    00432              i18n( "Close message" ), i18n( "&Discard" ), i18n("&Continue") );
    00433     if( rc == KMessageBox::No )
    00434       return;
    00435   }
    00436   KDialogBase::slotCancel();
    00437 }
    00438
    00439
    00440 QString KBugReport::text() const
    00441 {
    00442     kdDebug() << m_bgSeverity->selected()->name() << endl;
    00443     // Prepend the pseudo-headers to the contents of the mail
    00444   QString severity = QString::fromLatin1(m_bgSeverity->selected()->name());
    00445   QString appname = d->appcombo->currentText();
    00446   QString os = QString::fromLatin1("OS: %1 (%2)\n").
    00447                arg(KDE_COMPILING_OS).
    00448                arg(KDE_DISTRIBUTION_TEXT);
    00449   QString bodyText;
    00450   for(int i = 0; i < m_lineedit->numLines(); i++)
    00451   {
    00452      QString line = m_lineedit->textLine(i);
    00453      if (line.right(1) != "\n")
    00454         line += '\n';
    00455      bodyText += line;
    00456   }
    00457
    00458   if (severity == QString::fromLatin1("i18n") && KGlobal::locale()->language() != KLocale::defaultLanguage()) {
    00459       // Case 1 : i18n bug
    00460       QString package = QString::fromLatin1("i18n_%1").arg(KGlobal::locale()->language());
    00461       package = package.replace(QRegExp("_"), QString::fromLatin1("-"));
    00462       return QString::fromLatin1("Package: %1").arg(package) +
    00463           QString::fromLatin1("\n"
    00464                               "Application: %1\n"
    00465                               // not really i18n's version, so better here IMHO
    00466                               "Version: %2\n").arg(appname).arg(m_strVersion)+
    00467           os+QString::fromLatin1("\n")+bodyText;
    00468   } else {
    00469       appname = appname.replace(QRegExp("_"), QString::fromLatin1("-"));
    00470       // Case 2 : normal bug
    00471       return QString::fromLatin1("Package: %1\n"
    00472                                  "Version: %2\n"
    00473                                  "Severity: %3\n")
    00474           .arg(appname).arg(m_strVersion).arg(severity)+
    00475           QString::fromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+
    00476           os+QString::fromLatin1("\n")+bodyText;
    00477   }
    00478 }
    00479
    00480 bool KBugReport::sendBugReport()
    00481 {
    00482   QString recipient ( m_aboutData ?
    00483     m_aboutData->bugAddress() :
    00484     QString::fromLatin1("submit@bugs.kde.org") );
    00485
    00486   QString command;
    00487   command = locate("exe", "ksendbugmail");
    00488   if (command.isEmpty())
    00489       command = KStandardDirs::findExe( QString::fromLatin1("ksendbugmail") );
    00490
    00491   KTempFile outputfile;
    00492   outputfile.close();
    00493
    00494   QString subject = m_subject->text();
    00495   subject = subject.replace(QRegExp("\""), QString::fromLatin1("\\\""));
    00496   command += QString::fromLatin1(" --subject \"%1\" --recipient \"%2\" > %3").
    00497              arg(KProcess::quote(subject)).
    00498              arg(KProcess::quote(recipient)).
    00499              arg(outputfile.name());
    00500
    00501   fflush(stdin);
    00502   fflush(stderr);
    00503
    00504   FILE * fd = popen(command.local8Bit(), "w");
    00505   if (!fd)
    00506   {
    00507     kdError() << "Unable to open a pipe to " << command << endl;
    00508     return false;
    00509   }
    00510
    00511   QString btext = text();
    00512   fwrite(btext.ascii(),btext.length(),1,fd);
    00513   fflush(fd);
    00514
    00515   int error = pclose(fd);
    00516   kdDebug() << "exit status1 " << error << " " << (WIFEXITED(error)) << " " <<  WEXITSTATUS(error) << endl;
    00517
    00518   if ((WIFEXITED(error)) && WEXITSTATUS(error) == 1) {
    00519       QFile of(outputfile.name());
    00520       if (of.open(IO_ReadOnly )) {
    00521           QTextStream is(&of);
    00522           is.setEncoding(QTextStream::UnicodeUTF8);
    00523           QString line;
    00524           while (!is.eof())
    00525               line = is.readLine();
    00526           d->lastError = line;
    00527       } else {
    00528           d->lastError = QString::null;
    00529       }
    00530       outputfile.unlink();
    00531       return false;
    00532   }
    00533   outputfile.unlink();
    00534   return true;
    00535 }
    00536
    00537 void KBugReport::virtual_hook( int id, void* data )
    00538 { KDialogBase::virtual_hook( id, data ); }
    00539
    00540 #include "kbugreport.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:56:13 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001