00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kbugreport.h"
00021
00022 #include <QtCore/QProcess>
00023 #include <QtCore/QCoreApplication>
00024 #include <QtGui/QPushButton>
00025 #include <QtGui/QLayout>
00026 #include <QtGui/QRadioButton>
00027 #include <QtGui/QGroupBox>
00028 #include <QtGui/QCloseEvent>
00029
00030 #include <kaboutdata.h>
00031 #include <kcombobox.h>
00032 #include <ktoolinvocation.h>
00033 #include <kdebug.h>
00034 #include <klineedit.h>
00035 #include <klocale.h>
00036 #include <kmessagebox.h>
00037 #include <kstandarddirs.h>
00038 #include <kcomponentdata.h>
00039 #include <kurllabel.h>
00040 #include <ktextedit.h>
00041 #include <ktitlewidget.h>
00042
00043 #include <stdio.h>
00044 #include <pwd.h>
00045 #include <unistd.h>
00046 #include <sys/utsname.h>
00047
00048 #include "kdepackages.h"
00049 #include "kdeversion.h"
00050
00051 #include <config-compiler.h>
00052
00053 class KBugReportPrivate {
00054 public:
00055 KBugReportPrivate(KBugReport *q): q(q) {}
00056
00057 void _k_slotConfigureEmail();
00058 void _k_slotSetFrom();
00059 void _k_appChanged(int);
00060 void _k_updateUrl();
00061
00062 KBugReport *q;
00063 QProcess * m_process;
00064 const KAboutData * m_aboutData;
00065
00066 KTextEdit * m_lineedit;
00067 KLineEdit * m_subject;
00068 QLabel * m_from;
00069 QLabel * m_version;
00070 QString m_strVersion;
00071 QGroupBox * m_bgSeverity;
00072 QPushButton * m_configureEmail;
00073
00074 KComboBox *appcombo;
00075 QString lastError;
00076 QString kde_version;
00077 QString appname;
00078 QString os;
00079 KUrl url;
00080 QList<QRadioButton*> severityButtons;
00081 int currentSeverity() {
00082 for (int i=0;i<severityButtons.count();i++)
00083 if (severityButtons[i]->isChecked()) return i;
00084 return -1;
00085 }
00086 bool submitBugWeb;
00087 };
00088
00089 KBugReport::KBugReport( QWidget * _parent, bool modal, const KAboutData *aboutData )
00090 : KDialog( _parent ), d( new KBugReportPrivate(this) )
00091 {
00092 setCaption( i18n("Submit Bug Report") );
00093 setButtons( Ok | Cancel );
00094 showButtonSeparator(true);
00095 setModal(modal);
00096
00097
00098
00099 d->m_aboutData = aboutData ? aboutData
00100 : (KGlobal::activeComponent().isValid() ? KGlobal::activeComponent().aboutData()
00101 : KGlobal::mainComponent().aboutData());
00102 d->m_process = 0;
00103 QWidget * parent = new QWidget(this);
00104 d->submitBugWeb = false;
00105
00106 if ( d->m_aboutData->bugAddress() == QLatin1String("submit@bugs.kde.org") )
00107 {
00108
00109 d->submitBugWeb = true;
00110 setButtonGuiItem( Cancel, KStandardGuiItem::close() );
00111 }
00112
00113 QLabel * tmpLabel;
00114 QVBoxLayout * lay = new QVBoxLayout( parent);
00115
00116 KTitleWidget *title = new KTitleWidget( this );
00117 title->setText(i18n( "Submit Bug Report" ) );
00118 title->setPixmap( KIcon( "tools-report-bug" ).pixmap( 32 ) );
00119 lay->addWidget( title );
00120
00121 QGridLayout *glay = new QGridLayout();
00122 lay->addLayout(glay);
00123
00124 int row = 0;
00125
00126 if ( !d->submitBugWeb )
00127 {
00128
00129 QString qwtstr = i18n( "Your email address. If incorrect, use the Configure Email button to change it" );
00130 tmpLabel = new QLabel( i18nc("Email sender address", "From:"), parent );
00131 glay->addWidget( tmpLabel, row,0 );
00132 tmpLabel->setWhatsThis(qwtstr );
00133 d->m_from = new QLabel( parent );
00134 glay->addWidget( d->m_from, row, 1 );
00135 d->m_from->setWhatsThis(qwtstr );
00136
00137
00138
00139 d->m_configureEmail = new QPushButton( i18n("Configure Email..."),
00140 parent );
00141 connect( d->m_configureEmail, SIGNAL( clicked() ), this,
00142 SLOT( _k_slotConfigureEmail() ) );
00143 glay->addWidget( d->m_configureEmail, 0, 2, 3, 1, Qt::AlignTop|Qt::AlignRight );
00144
00145
00146 qwtstr = i18n( "The email address this bug report is sent to." );
00147 tmpLabel = new QLabel( i18nc("Email receiver address", "To:"), parent );
00148 glay->addWidget( tmpLabel, ++row,0 );
00149 tmpLabel->setWhatsThis(qwtstr );
00150 tmpLabel = new QLabel( d->m_aboutData->bugAddress(), parent );
00151 tmpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
00152 glay->addWidget( tmpLabel, row, 1 );
00153 tmpLabel->setWhatsThis(qwtstr );
00154
00155 setButtonGuiItem( Ok, KGuiItem( i18n("&Send"), "mail-send", i18n( "Send bug report." ),
00156 i18n( "Send this bug report to %1." , d->m_aboutData->bugAddress() ) ) );
00157 row++;
00158 }
00159 else
00160 {
00161 d->m_configureEmail = 0;
00162 d->m_from = 0;
00163 }
00164
00165
00166 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" );
00167 tmpLabel = new QLabel( i18n("Application: "), parent );
00168 glay->addWidget( tmpLabel, row, 0 );
00169 tmpLabel->setWhatsThis(qwtstr );
00170 d->appcombo = new KComboBox( false, parent );
00171 d->appcombo->setWhatsThis(qwtstr );
00172 QStringList packageList;
00173 for (int c = 0; packages[c]; ++c)
00174 packageList << QString::fromLatin1(packages[c]);
00175 d->appcombo->addItems(packageList);
00176 connect(d->appcombo, SIGNAL(activated(int)), SLOT(_k_appChanged(int)));
00177 d->appname = d->m_aboutData
00178 ? d->m_aboutData->productName()
00179 : qApp->applicationName() ;
00180 glay->addWidget( d->appcombo, row, 1 );
00181 int index = 0;
00182 for (; index < d->appcombo->count(); index++) {
00183 if (d->appcombo->itemText(index) == d->appname) {
00184 break;
00185 }
00186 }
00187 if (index == d->appcombo->count()) {
00188 d->appcombo->addItem(d->appname);
00189 }
00190 d->appcombo->setCurrentIndex(index);
00191
00192 tmpLabel->setWhatsThis(qwtstr );
00193
00194
00195 qwtstr = i18n( "The version of this application - please make sure that no newer version is available before sending a bug report" );
00196 tmpLabel = new QLabel( i18n("Version:"), parent );
00197 glay->addWidget( tmpLabel, ++row, 0 );
00198 tmpLabel->setWhatsThis(qwtstr );
00199 if (d->m_aboutData)
00200 d->m_strVersion = d->m_aboutData->version();
00201 else
00202 d->m_strVersion = i18n("no version set (programmer error!)");
00203 d->kde_version = QString::fromLatin1( KDE_VERSION_STRING );
00204 d->kde_version += ", " + QString::fromLatin1( KDE_DISTRIBUTION_TEXT );
00205 if ( !d->submitBugWeb )
00206 d->m_strVersion += ' ' + d->kde_version;
00207 d->m_version = new QLabel( d->m_strVersion, parent );
00208 d->m_version->setTextInteractionFlags(Qt::TextBrowserInteraction);
00209
00210 glay->addWidget( d->m_version, row, 1, 1, 2 );
00211 d->m_version->setWhatsThis(qwtstr );
00212
00213 tmpLabel = new QLabel(i18n("OS:"), parent);
00214 glay->addWidget( tmpLabel, ++row, 0 );
00215
00216 struct utsname unameBuf;
00217 uname( &unameBuf );
00218 d->os = QString::fromLatin1( unameBuf.sysname ) +
00219 " (" + QString::fromLatin1( unameBuf.machine ) + ") "
00220 "release " + QString::fromLatin1( unameBuf.release );
00221
00222 tmpLabel = new QLabel(d->os, parent);
00223 tmpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
00224 glay->addWidget( tmpLabel, row, 1, 1, 2 );
00225
00226 tmpLabel = new QLabel(i18n("Compiler:"), parent);
00227 glay->addWidget( tmpLabel, ++row, 0 );
00228 tmpLabel = new QLabel(QString::fromLatin1(KDE_COMPILER_VERSION), parent);
00229 tmpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
00230 glay->addWidget( tmpLabel, row, 1, 1, 2 );
00231
00232 if ( !d->submitBugWeb )
00233 {
00234
00235 d->m_bgSeverity = new QGroupBox( i18n("Se&verity"), parent );
00236 static const char * const sevNames[5] = { "critical", "grave", "normal", "wishlist", "i18n" };
00237 const QString sevTexts[5] = { i18n("Critical"), i18n("Grave"), i18nc("normal severity","Normal"), i18n("Wishlist"), i18n("Translation") };
00238 QHBoxLayout *severityLayout=new QHBoxLayout(d->m_bgSeverity);
00239 for (int i = 0 ; i < 5 ; i++ )
00240 {
00241
00242 QRadioButton *rb = new QRadioButton( sevTexts[i], d->m_bgSeverity);
00243 rb->setObjectName(sevNames[i] );
00244 d->severityButtons.append(rb);
00245 severityLayout->addWidget(rb);
00246 if (i==2) rb->setChecked(true);
00247 }
00248
00249 lay->addWidget( d->m_bgSeverity );
00250
00251
00252 QHBoxLayout * hlay = new QHBoxLayout();
00253 lay->addItem(hlay);
00254 tmpLabel = new QLabel( i18n("S&ubject: "), parent );
00255 hlay->addWidget( tmpLabel );
00256 d->m_subject = new KLineEdit( parent );
00257 d->m_subject->setClearButtonShown(true);
00258 d->m_subject->setFocus();
00259 tmpLabel->setBuddy( d->m_subject );
00260 hlay->addWidget( d->m_subject );
00261
00262 QString text = i18n("Enter the text (in English if possible) that you wish to submit for the "
00263 "bug report.\n"
00264 "If you press \"Send\", a mail message will be sent to the maintainer of "
00265 "this program.\n");
00266 QLabel * label = new QLabel( parent);
00267
00268 label->setText( text );
00269 lay->addWidget( label );
00270
00271
00272 d->m_lineedit = new KTextEdit( parent);
00273 d->m_lineedit->setMinimumHeight( 180 );
00274 d->m_lineedit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
00275 d->m_lineedit->setLineWrapMode(QTextEdit::WidgetWidth);
00276 d->m_lineedit->setCheckSpellingEnabled(true);
00277 d->m_lineedit->setSpellCheckingLanguage("en");
00278 lay->addWidget( d->m_lineedit, 10 );
00279
00280 d->_k_slotSetFrom();
00281 } else {
00282
00283
00284 lay->addSpacing(10);
00285 QString text = i18n("<qt>To submit a bug report, click on the button below. This will open a web browser "
00286 "window on <a href=\"http://bugs.kde.org\">http://bugs.kde.org</a> where you will find "
00287 "a form to fill in. The information displayed above will be transferred to that server.</qt>");
00288 QLabel * label = new QLabel( text, parent);
00289 label->setOpenExternalLinks( true );
00290 label->setTextInteractionFlags( Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard );
00291 label->setWordWrap( true );
00292 lay->addWidget( label );
00293 lay->addSpacing(10);
00294
00295 d->appcombo->setFocus();
00296
00297 d->_k_updateUrl();
00298
00299 setButtonText(Ok, i18n("&Launch Bug Report Wizard"));
00300 setButtonIcon(Ok, KIcon("tools-report-bug"));
00301 }
00302 parent->setMinimumHeight( parent->sizeHint().height() + 20 );
00303 setMainWidget(parent);
00304 }
00305
00306 KBugReport::~KBugReport()
00307 {
00308 delete d;
00309 }
00310
00311 QString KBugReport::messageBody() const
00312 {
00313 if ( !d->submitBugWeb )
00314 return d->m_lineedit->toPlainText();
00315 else
00316 return QString();
00317 }
00318
00319 void KBugReport::setMessageBody(const QString &messageBody)
00320 {
00321 if ( !d->submitBugWeb )
00322 d->m_lineedit->setPlainText(messageBody);
00323 }
00324
00325 void KBugReportPrivate::_k_updateUrl()
00326 {
00327 url = KUrl( "https://bugs.kde.org/wizard.cgi" );
00328 url.addQueryItem( "os", os );
00329 url.addQueryItem( "compiler", KDE_COMPILER_VERSION );
00330 url.addQueryItem( "kdeVersion", kde_version );
00331 url.addQueryItem( "appVersion", m_strVersion );
00332 url.addQueryItem( "package", appcombo->currentText() );
00333 url.addQueryItem( "kbugreport", "1" );
00334 }
00335
00336 void KBugReportPrivate::_k_appChanged(int i)
00337 {
00338 QString appName = appcombo->itemText(i);
00339 int index = appName.indexOf( '/' );
00340 if ( index > 0 )
00341 appName = appName.left( index );
00342 kDebug() << "appName " << appName;
00343
00344 if (appname == appName && m_aboutData)
00345 m_strVersion = m_aboutData->version();
00346 else
00347 m_strVersion = i18nc("unknown program name", "unknown");
00348
00349 if ( !submitBugWeb )
00350 m_strVersion += ' ' + kde_version;
00351
00352 m_version->setText(m_strVersion);
00353 if ( submitBugWeb )
00354 _k_updateUrl();
00355 }
00356
00357 void KBugReportPrivate::_k_slotConfigureEmail()
00358 {
00359 if (m_process) return;
00360 m_process = new QProcess;
00361 QObject::connect( m_process, SIGNAL(finished( int, QProcess::ExitStatus )), q, SLOT(_k_slotSetFrom()) );
00362 m_process->start( QString::fromLatin1("kcmshell4"), QStringList() << QString::fromLatin1("kcm_useraccount") );
00363 if ( !m_process->waitForStarted() )
00364 {
00365 kDebug() << "Couldn't start kcmshell4..";
00366 delete m_process;
00367 m_process = 0;
00368 return;
00369 }
00370 m_configureEmail->setEnabled(false);
00371 }
00372
00373 void KBugReportPrivate::_k_slotSetFrom()
00374 {
00375 delete m_process;
00376 m_process = 0;
00377 m_configureEmail->setEnabled(true);
00378
00379
00380 KConfig emailConf( QString::fromLatin1("emaildefaults") );
00381
00382 KConfigGroup cg(&emailConf, "Defaults");
00383
00384 QString profile = QString::fromLatin1("PROFILE_");
00385 profile += cg.readEntry( QString::fromLatin1("Profile"),
00386 QString::fromLatin1("Default") );
00387
00388 KConfigGroup profileGrp(&emailConf, profile );
00389 QString fromaddr = profileGrp.readEntry( "EmailAddress" );
00390 if (fromaddr.isEmpty()) {
00391 struct passwd *p;
00392 p = getpwuid(getuid());
00393 fromaddr = QString::fromLatin1(p->pw_name);
00394 } else {
00395 QString name = profileGrp.readEntry( "FullName" );
00396 if (!name.isEmpty())
00397 fromaddr = name + QString::fromLatin1(" <") + fromaddr + QString::fromLatin1(">");
00398 }
00399 m_from->setText( fromaddr );
00400 }
00401
00402 void KBugReport::accept()
00403 {
00404 if ( d->submitBugWeb ) {
00405 KToolInvocation::invokeBrowser( d->url.url() );
00406 return;
00407 }
00408
00409 if( d->m_lineedit->toPlainText().isEmpty() ||
00410 d->m_subject->text().isEmpty() )
00411 {
00412 QString msg = i18n("You must specify both a subject and a description "
00413 "before the report can be sent.");
00414 KMessageBox::error(this,msg);
00415 return;
00416 }
00417
00418 switch ( d->currentSeverity())
00419 {
00420 case 0:
00421 if ( KMessageBox::questionYesNo( this, i18n(
00422 "<p>You chose the severity <b>Critical</b>. "
00423 "Please note that this severity is intended only for bugs that</p>"
00424 "<ul><li>break unrelated software on the system (or the whole system)</li>"
00425 "<li>cause serious data loss</li>"
00426 "<li>introduce a security hole on the system where the affected package is installed</li></ul>\n"
00427 "<p>Does the bug you are reporting cause any of the above damage? "
00428 "If it does not, please select a lower severity. Thank you!</p>" ),QString(),KStandardGuiItem::cont(),KStandardGuiItem::cancel() ) == KMessageBox::No )
00429 return;
00430 break;
00431 case 1:
00432 if ( KMessageBox::questionYesNo( this, i18n(
00433 "<p>You chose the severity <b>Grave</b>. "
00434 "Please note that this severity is intended only for bugs that</p>"
00435 "<ul><li>make the package in question unusable or mostly so</li>"
00436 "<li>cause data loss</li>"
00437 "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n"
00438 "<p>Does the bug you are reporting cause any of the above damage? "
00439 "If it does not, please select a lower severity. Thank you!</p>" ),QString(),KStandardGuiItem::cont(),KStandardGuiItem::cancel() ) == KMessageBox::No )
00440 return;
00441 break;
00442 default:
00443 break;
00444 }
00445 if( !sendBugReport() )
00446 {
00447 QString msg = i18n("Unable to send the bug report.\n"
00448 "Please submit a bug report manually...\n"
00449 "See http://bugs.kde.org/ for instructions.");
00450 KMessageBox::error(this, msg + "\n\n" + d->lastError);
00451 return;
00452 }
00453
00454 KMessageBox::information(this,
00455 i18n("Bug report sent, thank you for your input."));
00456 KDialog::accept();
00457 }
00458
00459 void KBugReport::closeEvent( QCloseEvent * e)
00460 {
00461 if( !d->submitBugWeb && ( (d->m_lineedit->toPlainText().length()>0) || d->m_subject->isModified() ) )
00462 {
00463 int rc = KMessageBox::warningYesNo( this,
00464 i18n( "Close and discard\nedited message?" ),
00465 i18n( "Close Message" ), KStandardGuiItem::discard(), KStandardGuiItem::cont() );
00466 if( rc == KMessageBox::No )
00467 {
00468 e->ignore();
00469 return;
00470 }
00471 }
00472 KDialog::closeEvent(e);
00473 }
00474
00475
00476 QString KBugReport::text() const
00477 {
00478 kDebug() << d->severityButtons[d->currentSeverity()]->objectName();
00479
00480 QString severity = d->severityButtons[d->currentSeverity()]->objectName();
00481 QString appname = d->appcombo->currentText();
00482 QString os = QString::fromLatin1("OS: %1 (%2)\n").
00483 arg(KDE_COMPILING_OS).
00484 arg(KDE_DISTRIBUTION_TEXT);
00485 QString bodyText;
00486
00487
00488
00489
00490
00491
00492
00493
00494 bodyText=d->m_lineedit->toPlainText();
00495 if (bodyText.length()>0)
00496 if (bodyText[bodyText.length()-1]!='\n') bodyText+='\n';
00497 if (severity == QLatin1String("i18n") && KGlobal::locale()->language() != KLocale::defaultLanguage()) {
00498
00499 QString package = QString::fromLatin1("i18n_%1").arg(KGlobal::locale()->language());
00500 package = package.replace('_', '-');
00501 return QString::fromLatin1("Package: %1").arg(package) +
00502 QString::fromLatin1("\n"
00503 "Application: %1\n"
00504
00505 "Version: %2\n").arg(appname).arg(d->m_strVersion)+
00506 os+QString::fromLatin1("\n")+bodyText;
00507 } else {
00508 appname = appname.replace('_', '-');
00509
00510 return QString::fromLatin1("Package: %1\n"
00511 "Version: %2\n"
00512 "Severity: %3\n")
00513 .arg(appname).arg(d->m_strVersion).arg(severity)+
00514 QString::fromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+
00515 os+QString::fromLatin1("\n")+bodyText;
00516 }
00517 }
00518
00519 bool KBugReport::sendBugReport()
00520 {
00521 QString recipient ( d->m_aboutData ?
00522 d->m_aboutData->bugAddress() :
00523 QString::fromLatin1("submit@bugs.kde.org") );
00524
00525 QString command;
00526 command = KStandardDirs::locate("exe", "ksendbugmail");
00527 if (command.isEmpty())
00528 command = KStandardDirs::findExe( QString::fromLatin1("ksendbugmail") );
00529
00530 QProcess proc;
00531 QStringList args;
00532 args << "--subject" << d->m_subject->text() << "--recipient" << recipient;
00533 proc.start( command, args );
00534
00535 if (!proc.waitForStarted())
00536 {
00537 kError() << "Unable to open a pipe to " << command << endl;
00538 return false;
00539 }
00540 proc.write( text().toUtf8() );
00541 proc.closeWriteChannel();
00542
00543 proc.waitForFinished();
00544 kDebug() << "kbugreport: sendbugmail exit, status " << proc.exitStatus() << " code " << proc.exitCode();
00545
00546 QByteArray line;
00547 if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() != 0) {
00548
00549 while (!proc.atEnd())
00550 line = proc.readLine();
00551 d->lastError = QString::fromUtf8( line );
00552 return false;
00553 }
00554 return true;
00555 }
00556
00557
00558 #include "kbugreport.moc"