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