00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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,
00074 true
00075 )
00076 {
00077 d = new KBugReportPrivate;
00078
00079
00080
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
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
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
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
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
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()) {
00165 d->appcombo->insertItem(d->appname);
00166 }
00167 d->appcombo->setCurrentItem(index);
00168
00169 QWhatsThis::add( tmpLabel, qwtstr );
00170
00171
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
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
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
00215 QRadioButton *rb = new QRadioButton( sevTexts[i], m_bgSeverity, sevNames[i] );
00216 if (i==2) rb->setChecked(true);
00217 }
00218
00219 lay->addWidget( m_bgSeverity );
00220
00221
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
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251 label->setText( text );
00252 lay->addWidget( label );
00253
00254
00255 m_lineedit = new QMultiLineEdit( parent, "QMultiLineEdit" );
00256 m_lineedit->setMinimumHeight( 180 );
00257 m_lineedit->setWordWrap(QMultiLineEdit::WidgetWidth);
00258 lay->addWidget( m_lineedit, 10 );
00259
00260
00261 hlay = new QHBoxLayout( lay, 0 );
00262
00263 text = i18n("Please check that the bug you are about to report is not already listed at ");
00264 label = new QLabel( text, parent, "label");
00265 hlay->addWidget( label, 0, AlignBottom );
00266 hlay->addSpacing(1);
00267
00268 text = "http://bugs.kde.org/";
00269 KURLLabel *url = new KURLLabel( parent );
00270 url->setText(text);
00271 url->setURL(text);
00272 connect( url, SIGNAL(leftClickedURL(const QString &)),
00273 this, SLOT(slotUrlClicked(const QString &)));
00274 hlay->addWidget( url, 0, AlignBottom );
00275
00276 hlay->addStretch( 10 );
00277
00278
00279 label->setFixedHeight( fontMetrics().lineSpacing() );
00280 url->setFixedHeight( fontMetrics().lineSpacing());
00281
00282 slotSetFrom();
00283 } else {
00284
00285
00286 lay->addSpacing(20);
00287 QString text = i18n("To submit a bug report, click on the link below.\n"
00288 "This will open a web browser window on http://bugs.kde.org where you'll find a form to fill in.\n"
00289 "The information displayed above will be transferred to that server.");
00290 QLabel * label = new QLabel( text, parent, "label");
00291 lay->addWidget( label );
00292 lay->addSpacing(20);
00293
00294 updateURL();
00295 d->webFormLabel->setText( "http://bugs.kde.org/wizard/index.php" );
00296 lay->addWidget( d->webFormLabel );
00297 lay->addSpacing(20);
00298
00299 connect( d->webFormLabel, SIGNAL(leftClickedURL(const QString &)),
00300 this, SLOT(slotUrlClicked(const QString &)));
00301 }
00302 }
00303
00304 KBugReport::~KBugReport()
00305 {
00306 delete d;
00307 }
00308
00309 void KBugReport::updateURL()
00310 {
00311 QString url = QString::fromLatin1("http://bugs.kde.org/wizard/index.php");
00312 url += "?os=";
00313 url += KURL::encode_string( d->os );
00314 url += "&compiler=";
00315 url += KURL::encode_string( QString::fromLatin1(KDE_COMPILER_VERSION) );
00316 url += "&version=";
00317 url += KURL::encode_string( m_strVersion );
00318 url += "&package=";
00319 url += KURL::encode_string( d->appcombo->currentText() );
00320 url += "&kbugreport=1";
00321 d->webFormLabel->setURL( url );
00322 }
00323
00324 void KBugReport::appChanged(int i)
00325 {
00326 if (d->appname == d->appcombo->text(i) && m_aboutData)
00327 m_strVersion = m_aboutData->version();
00328 else
00329 m_strVersion = i18n("unknown program name", "unknown");
00330
00331 m_strVersion += d->kde_version;
00332 m_version->setText(m_strVersion);
00333 if ( d->webFormLabel )
00334 updateURL();
00335 }
00336
00337 void KBugReport::slotConfigureEmail()
00338 {
00339 if (m_process) return;
00340 m_process = new KProcess;
00341 *m_process << QString::fromLatin1("kcmshell") << QString::fromLatin1("email");
00342 connect(m_process, SIGNAL(processExited(KProcess *)), SLOT(slotSetFrom()));
00343 if (!m_process->start())
00344 {
00345 kdDebug() << "Couldn't start kcmshell.." << endl;
00346 delete m_process;
00347 m_process = 0;
00348 return;
00349 }
00350 m_configureEmail->setEnabled(false);
00351 }
00352
00353 void KBugReport::slotSetFrom()
00354 {
00355 delete m_process;
00356 m_process = 0;
00357 m_configureEmail->setEnabled(true);
00358
00359
00360 KConfig emailConf( QString::fromLatin1("emaildefaults") );
00361
00362
00363 emailConf.setGroup( QString::fromLatin1("Defaults") );
00364 QString profile = QString::fromLatin1("PROFILE_");
00365 profile += emailConf.readEntry( QString::fromLatin1("Profile"),
00366 QString::fromLatin1("Default") );
00367
00368 emailConf.setGroup( profile );
00369 QString fromaddr = emailConf.readEntry( QString::fromLatin1("EmailAddress") );
00370 if (fromaddr.isEmpty()) {
00371 struct passwd *p;
00372 p = getpwuid(getuid());
00373 fromaddr = QString::fromLatin1(p->pw_name);
00374 } else {
00375 QString name = emailConf.readEntry( QString::fromLatin1("FullName"));
00376 if (!name.isEmpty())
00377 fromaddr = name + QString::fromLatin1(" <") + fromaddr + QString::fromLatin1(">");
00378 }
00379 m_from->setText( fromaddr );
00380 }
00381
00382 void KBugReport::slotUrlClicked(const QString &urlText)
00383 {
00384 if ( kapp )
00385 kapp->invokeBrowser( urlText );
00386
00387
00388
00389 if ( d->webFormLabel )
00390 KDialogBase::slotCancel();
00391 }
00392
00393
00394 void KBugReport::slotOk( void )
00395 {
00396 if ( d->webFormLabel)
00397 return;
00398
00399 if( m_lineedit->text().isEmpty() == true ||
00400 m_subject->text().isEmpty() == true )
00401 {
00402 QString msg = i18n("You must specify both a subject and a description "
00403 "before the report can be sent.");
00404 KMessageBox::error(this,msg);
00405 return;
00406 }
00407
00408 switch ( m_bgSeverity->id( m_bgSeverity->selected() ) )
00409 {
00410 case 0:
00411 if ( KMessageBox::questionYesNo( this, i18n(
00412 "<p>You chose the severity <b>Critical</b>. "
00413 "Please note that this severity is intended only for bugs that</p>"
00414 "<ul><li>break unrelated software on the system (or the whole system)</li>"
00415 "<li>cause serious data loss</li>"
00416 "<li>introduce a security hole on the system where the affected package is installed</li></ul>\n"
00417 "<p>Does the bug you are reporting cause any of the above damage? "
00418 "If it does not, please select a lower severity. Thank you!</p>" ) ) == KMessageBox::No )
00419 return;
00420 break;
00421 case 1:
00422 if ( KMessageBox::questionYesNo( this, i18n(
00423 "<p>You chose the severity <b>Grave</b>. "
00424 "Please note that this severity is intended only for bugs that</p>"
00425 "<ul><li>make the package in question unusable or mostly so</li>"
00426 "<li>cause data loss</li>"
00427 "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n"
00428 "<p>Does the bug you are reporting cause any of the above damage? "
00429 "If it does not, please select a lower severity. Thank you!</p>" ) ) == KMessageBox::No )
00430 return;
00431 break;
00432 }
00433 if( !sendBugReport() )
00434 {
00435 QString msg = i18n(""
00436 "Unable to send the bug report.\n"
00437 "Please submit a bug report manually...\n"
00438 "See http://bugs.kde.org/ for instructions.");
00439 KMessageBox::error(this, msg + "\n\n" + d->lastError);
00440 return;
00441 }
00442
00443 KMessageBox::information(this,
00444 i18n("Bug report sent, thank you for your input."));
00445 accept();
00446 }
00447
00448 void KBugReport::slotCancel()
00449 {
00450 if( !d->webFormLabel && ( m_lineedit->edited() || m_subject->edited() ) )
00451 {
00452 int rc = KMessageBox::warningYesNo( this,
00453 i18n( "Close and discard\nedited message?" ),
00454 i18n( "Close message" ), i18n( "&Discard" ), i18n("&Continue") );
00455 if( rc == KMessageBox::No )
00456 return;
00457 }
00458 KDialogBase::slotCancel();
00459 }
00460
00461
00462 QString KBugReport::text() const
00463 {
00464 kdDebug() << m_bgSeverity->selected()->name() << endl;
00465
00466 QString severity = QString::fromLatin1(m_bgSeverity->selected()->name());
00467 QString appname = d->appcombo->currentText();
00468 QString os = QString::fromLatin1("OS: %1 (%2)\n").
00469 arg(KDE_COMPILING_OS).
00470 arg(KDE_DISTRIBUTION_TEXT);
00471 QString bodyText;
00472 for(int i = 0; i < m_lineedit->numLines(); i++)
00473 {
00474 QString line = m_lineedit->textLine(i);
00475 if (line.right(1) != "\n")
00476 line += '\n';
00477 bodyText += line;
00478 }
00479
00480 if (severity == QString::fromLatin1("i18n") && KGlobal::locale()->language() != KLocale::defaultLanguage()) {
00481
00482 QString package = QString::fromLatin1("i18n_%1").arg(KGlobal::locale()->language());
00483 package = package.replace(QRegExp("_"), QString::fromLatin1("-"));
00484 return QString::fromLatin1("Package: %1").arg(package) +
00485 QString::fromLatin1("\n"
00486 "Application: %1\n"
00487
00488 "Version: %2\n").arg(appname).arg(m_strVersion)+
00489 os+QString::fromLatin1("\n")+bodyText;
00490 } else {
00491 appname = appname.replace(QRegExp("_"), QString::fromLatin1("-"));
00492
00493 return QString::fromLatin1("Package: %1\n"
00494 "Version: %2\n"
00495 "Severity: %3\n")
00496 .arg(appname).arg(m_strVersion).arg(severity)+
00497 QString::fromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+
00498 os+QString::fromLatin1("\n")+bodyText;
00499 }
00500 }
00501
00502 bool KBugReport::sendBugReport()
00503 {
00504 QString recipient ( m_aboutData ?
00505 m_aboutData->bugAddress() :
00506 QString::fromLatin1("submit@bugs.kde.org") );
00507
00508 QString command;
00509 command = locate("exe", "ksendbugmail");
00510 if (command.isEmpty())
00511 command = KStandardDirs::findExe( QString::fromLatin1("ksendbugmail") );
00512
00513 KTempFile outputfile;
00514 outputfile.close();
00515
00516 QString subject = m_subject->text();
00517 subject = subject.replace(QRegExp("\""), QString::fromLatin1("\\\""));
00518 command += QString::fromLatin1(" --subject \"%1\" --recipient \"%2\" > %3").
00519 arg(KProcess::quote(subject)).
00520 arg(KProcess::quote(recipient)).
00521 arg(outputfile.name());
00522
00523 fflush(stdin);
00524 fflush(stderr);
00525
00526 FILE * fd = popen(command.local8Bit(), "w");
00527 if (!fd)
00528 {
00529 kdError() << "Unable to open a pipe to " << command << endl;
00530 return false;
00531 }
00532
00533 QString btext = text();
00534 fwrite(btext.ascii(),btext.length(),1,fd);
00535 fflush(fd);
00536
00537 int error = pclose(fd);
00538 kdDebug() << "exit status1 " << error << " " << (WIFEXITED(error)) << " " << WEXITSTATUS(error) << endl;
00539
00540 if ((WIFEXITED(error)) && WEXITSTATUS(error) == 1) {
00541 QFile of(outputfile.name());
00542 if (of.open(IO_ReadOnly )) {
00543 QTextStream is(&of);
00544 is.setEncoding(QTextStream::UnicodeUTF8);
00545 QString line;
00546 while (!is.eof())
00547 line = is.readLine();
00548 d->lastError = line;
00549 } else {
00550 d->lastError = QString::null;
00551 }
00552 outputfile.unlink();
00553 return false;
00554 }
00555 outputfile.unlink();
00556 return true;
00557 }
00558
00559 void KBugReport::virtual_hook( int id, void* data )
00560 { KDialogBase::virtual_hook( id, data ); }
00561
00562 #include "kbugreport.moc"