kdeui Library API Documentation

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"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:02 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001