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