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., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include <tqhbuttongroup.h> 00021 #include <tqpushbutton.h> 00022 #include <tqlabel.h> 00023 #include <tqlayout.h> 00024 #include <tqmultilineedit.h> 00025 #include <tqradiobutton.h> 00026 #include <tqwhatsthis.h> 00027 #include <tqregexp.h> 00028 00029 #include <tdeaboutdata.h> 00030 #include <tdeapplication.h> 00031 #include <tdeconfig.h> 00032 #include <kdebug.h> 00033 #include <klineedit.h> 00034 #include <tdelocale.h> 00035 #include <tdemessagebox.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 <tdetempfile.h> 00054 #include <tqtextstream.h> 00055 #include <tqfile.h> 00056 00057 class KBugReportPrivate { 00058 public: 00059 KComboBox *appcombo; 00060 TQString lastError; 00061 TQString tde_version; 00062 TQString appname; 00063 TQString os; 00064 TQPushButton *submitBugButton; 00065 KURL url; 00066 }; 00067 00068 KBugReport::KBugReport( TQWidget * parentw, bool modal, const TDEAboutData *aboutData ) 00069 : KDialogBase( Plain, 00070 i18n("Submit Bug Report"), 00071 Ok | Cancel, 00072 Ok, 00073 parentw, 00074 "KBugReport", 00075 modal, // modal 00076 true // separator 00077 ) 00078 { 00079 d = new KBugReportPrivate; 00080 00081 // Use supplied aboutdata, otherwise the one from the active instance 00082 // otherwise the TDEGlobal one. _activeInstance should neved be 0L in theory. 00083 m_aboutData = aboutData 00084 ? aboutData 00085 : ( TDEGlobal::_activeInstance ? TDEGlobal::_activeInstance->aboutData() 00086 : TDEGlobal::instance()->aboutData() ); 00087 m_process = 0; 00088 TQWidget * parent = plainPage(); 00089 d->submitBugButton = 0; 00090 00091 //if ( m_aboutData->bugAddress() == TQString::fromLatin1("submit@bugs.trinitydesktop.org") ) 00092 //{ 00093 // // This is a core KDE application -> redirect to the web form 00094 // Always redirect to the Web form for Trinity 00095 d->submitBugButton = new TQPushButton( parent ); 00096 setButtonCancel( KStdGuiItem::close() ); 00097 //} 00098 00099 TQLabel * tmpLabel; 00100 TQVBoxLayout * lay = new TQVBoxLayout( parent, 0, spacingHint() ); 00101 00102 TQGridLayout *glay = new TQGridLayout( lay, 4, 3 ); 00103 glay->setColStretch( 1, 10 ); 00104 glay->setColStretch( 2, 10 ); 00105 00106 int row = 0; 00107 00108 if ( !d->submitBugButton ) 00109 { 00110 // From 00111 TQString qwtstr = i18n( "Your email address. If incorrect, use the Configure Email button to change it" ); 00112 tmpLabel = new TQLabel( i18n("From:"), parent ); 00113 glay->addWidget( tmpLabel, row,0 ); 00114 TQWhatsThis::add( tmpLabel, qwtstr ); 00115 m_from = new TQLabel( parent ); 00116 glay->addWidget( m_from, row, 1 ); 00117 TQWhatsThis::add( m_from, qwtstr ); 00118 00119 00120 // Configure email button 00121 m_configureEmail = new TQPushButton( i18n("Configure Email..."), 00122 parent ); 00123 connect( m_configureEmail, TQT_SIGNAL( clicked() ), this, 00124 TQT_SLOT( slotConfigureEmail() ) ); 00125 glay->addMultiCellWidget( m_configureEmail, 0, 2, 2, 2, (TQ_Alignment)(AlignTop|AlignRight) ); 00126 00127 // To 00128 qwtstr = i18n( "The email address this bug report is sent to." ); 00129 tmpLabel = new TQLabel( i18n("To:"), parent ); 00130 glay->addWidget( tmpLabel, ++row,0 ); 00131 TQWhatsThis::add( tmpLabel, qwtstr ); 00132 tmpLabel = new TQLabel( m_aboutData->bugAddress(), parent ); 00133 glay->addWidget( tmpLabel, row, 1 ); 00134 TQWhatsThis::add( tmpLabel, qwtstr ); 00135 00136 setButtonOK( KGuiItem( i18n("&Send"), "mail-send", i18n( "Send bug report." ), 00137 i18n( "Send this bug report to %1." ).arg( m_aboutData->bugAddress() ) ) ); 00138 00139 } 00140 else 00141 { 00142 m_configureEmail = 0; 00143 m_from = 0; 00144 showButtonOK( false ); 00145 } 00146 00147 // Program name 00148 TQString 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" ); 00149 tmpLabel = new TQLabel( i18n("Application: "), parent ); 00150 glay->addWidget( tmpLabel, ++row, 0 ); 00151 TQWhatsThis::add( tmpLabel, qwtstr ); 00152 d->appcombo = new KComboBox( false, parent, "app"); 00153 TQWhatsThis::add( d->appcombo, qwtstr ); 00154 d->appcombo->insertStrList((const char**)packages); 00155 connect(d->appcombo, TQT_SIGNAL(activated(int)), TQT_SLOT(appChanged(int))); 00156 d->appname = TQString::fromLatin1( m_aboutData 00157 ? m_aboutData->productName() 00158 : tqApp->name() ); 00159 glay->addWidget( d->appcombo, row, 1 ); 00160 int index = 0; 00161 for (; index < d->appcombo->count(); index++) { 00162 if (d->appcombo->text(index) == d->appname) { 00163 break; 00164 } 00165 } 00166 if (index == d->appcombo->count()) { // not present 00167 d->appcombo->insertItem(d->appname); 00168 } 00169 d->appcombo->setCurrentItem(index); 00170 00171 TQWhatsThis::add( tmpLabel, qwtstr ); 00172 00173 // Version 00174 qwtstr = i18n( "The version of this application - please make sure that no newer version is available before sending a bug report" ); 00175 tmpLabel = new TQLabel( i18n("Version:"), parent ); 00176 glay->addWidget( tmpLabel, ++row, 0 ); 00177 TQWhatsThis::add( tmpLabel, qwtstr ); 00178 if (m_aboutData) 00179 m_strVersion = m_aboutData->version(); 00180 else 00181 m_strVersion = i18n("no version set (programmer error!)"); 00182 d->tde_version = TQString::fromLatin1( TDE_VERSION_STRING ); 00183 if (TQString::fromLatin1( KDE_DISTRIBUTION_TEXT ) != "") 00184 d->tde_version += ", " + TQString::fromLatin1( KDE_DISTRIBUTION_TEXT ); 00185 if ( !d->submitBugButton ) 00186 m_strVersion += " " + d->tde_version; 00187 m_version = new TQLabel( m_strVersion, parent ); 00188 //glay->addWidget( m_version, row, 1 ); 00189 glay->addMultiCellWidget( m_version, row, row, 1, 2 ); 00190 TQWhatsThis::add( m_version, qwtstr ); 00191 00192 tmpLabel = new TQLabel(i18n("OS:"), parent); 00193 glay->addWidget( tmpLabel, ++row, 0 ); 00194 00195 struct utsname unameBuf; 00196 uname( &unameBuf ); 00197 d->os = TQString::fromLatin1( unameBuf.sysname ) + 00198 " (" + TQString::fromLatin1( unameBuf.machine ) + ") " 00199 "release " + TQString::fromLatin1( unameBuf.release ); 00200 00201 tmpLabel = new TQLabel(d->os, parent); 00202 glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 ); 00203 00204 tmpLabel = new TQLabel(i18n("Compiler:"), parent); 00205 glay->addWidget( tmpLabel, ++row, 0 ); 00206 tmpLabel = new TQLabel(TQString::fromLatin1(KDE_COMPILER_VERSION), parent); 00207 glay->addMultiCellWidget( tmpLabel, row, row, 1, 2 ); 00208 00209 if ( !d->submitBugButton ) 00210 { 00211 // Severity 00212 m_bgSeverity = new TQHButtonGroup( i18n("Se&verity"), parent ); 00213 static const char * const sevNames[5] = { "critical", "grave", "normal", "wishlist", "i18n" }; 00214 const TQString sevTexts[5] = { i18n("Critical"), i18n("Grave"), i18n("normal severity","Normal"), i18n("Wishlist"), i18n("Translation") }; 00215 00216 for (int i = 0 ; i < 5 ; i++ ) 00217 { 00218 // Store the severity string as the name 00219 TQRadioButton *rb = new TQRadioButton( sevTexts[i], m_bgSeverity, sevNames[i] ); 00220 if (i==2) rb->setChecked(true); // default : "normal" 00221 } 00222 00223 lay->addWidget( m_bgSeverity ); 00224 00225 // Subject 00226 TQHBoxLayout * hlay = new TQHBoxLayout( lay ); 00227 tmpLabel = new TQLabel( i18n("S&ubject: "), parent ); 00228 hlay->addWidget( tmpLabel ); 00229 m_subject = new KLineEdit( parent ); 00230 m_subject->setFocus(); 00231 tmpLabel->setBuddy(m_subject); 00232 hlay->addWidget( m_subject ); 00233 00234 TQString text = i18n("Enter the text (in English if possible) that you wish to submit for the " 00235 "bug report.\n" 00236 "If you press \"Send\", a mail message will be sent to the maintainer of " 00237 "this program.\n"); 00238 TQLabel * label = new TQLabel( parent, "label" ); 00239 00240 label->setText( text ); 00241 lay->addWidget( label ); 00242 00243 // The multiline-edit 00244 m_lineedit = new TQMultiLineEdit( parent, TQMULTILINEEDIT_OBJECT_NAME_STRING ); 00245 m_lineedit->setMinimumHeight( 180 ); // make it big 00246 m_lineedit->setWordWrap(TQMultiLineEdit::WidgetWidth); 00247 lay->addWidget( m_lineedit, 10 /*stretch*/ ); 00248 00249 slotSetFrom(); 00250 } else { 00251 // Point to the web form 00252 00253 lay->addSpacing(10); 00254 TQString text = i18n("Reporting bugs and requesting enhancements are maintained using the Bugzilla reporting system.\n" 00255 "You'll need a login account and password to use the reporting system.\n" 00256 "To control spam and rogue elements the login requires a valid email address.\n" 00257 "Consider using any large email service if you want to avoid using your private email address.\n" 00258 "\n" 00259 "Selecting the button below opens your web browser to http://bugs.trinitydesktop.org,\n" 00260 "where you will find the report form.\n" 00261 "The information displayed above will be transferred to the reporting system.\n" 00262 "Session cookies must be enabled to use the reporting system.\n" 00263 "\n" 00264 "Thank you for helping!"); 00265 TQLabel * label = new TQLabel( text, parent, "label"); 00266 lay->addWidget( label ); 00267 lay->addSpacing(10); 00268 00269 updateURL(); 00270 d->submitBugButton->setText( i18n("&Launch Bug Report Wizard") ); 00271 d->submitBugButton->setSizePolicy(TQSizePolicy::Fixed,TQSizePolicy::Fixed); 00272 lay->addWidget( d->submitBugButton ); 00273 lay->addSpacing(10); 00274 00275 connect( d->submitBugButton, TQT_SIGNAL(clicked()), 00276 this, TQT_SLOT(slotOk())); 00277 } 00278 } 00279 00280 KBugReport::~KBugReport() 00281 { 00282 delete d; 00283 } 00284 00285 void KBugReport::updateURL() 00286 { 00287 KURL url ( "http://bugs.trinitydesktop.org/enter_bug.cgi" ); 00288 url.addQueryItem( "product", "TDE" ); 00289 url.addQueryItem( "op_sys", d->os ); 00290 url.addQueryItem( "cf_kde_compiler", KDE_COMPILER_VERSION ); 00291 url.addQueryItem( "cf_tde_version", d->tde_version ); 00292 url.addQueryItem( "cf_kde_appversion", m_strVersion ); 00293 url.addQueryItem( "cf_kde_package", d->appcombo->currentText() ); 00294 url.addQueryItem( "cf_kde_kbugreport", "1" ); 00295 d->url = url; 00296 } 00297 00298 void KBugReport::appChanged(int i) 00299 { 00300 TQString appName = d->appcombo->text(i); 00301 int index = appName.find( '/' ); 00302 if ( index > 0 ) 00303 appName = appName.left( index ); 00304 kdDebug() << "appName " << appName << endl; 00305 00306 if (d->appname == appName && m_aboutData) 00307 m_strVersion = m_aboutData->version(); 00308 else 00309 m_strVersion = i18n("unknown program name", "unknown"); 00310 00311 if ( !d->submitBugButton ) 00312 m_strVersion += d->tde_version; 00313 00314 m_version->setText(m_strVersion); 00315 if ( d->submitBugButton ) 00316 updateURL(); 00317 } 00318 00319 void KBugReport::slotConfigureEmail() 00320 { 00321 if (m_process) return; 00322 m_process = new TDEProcess; 00323 *m_process << TQString::fromLatin1("tdecmshell") << TQString::fromLatin1("kcm_useraccount"); 00324 connect(m_process, TQT_SIGNAL(processExited(TDEProcess *)), TQT_SLOT(slotSetFrom())); 00325 if (!m_process->start()) 00326 { 00327 kdDebug() << "Couldn't start tdecmshell.." << endl; 00328 delete m_process; 00329 m_process = 0; 00330 return; 00331 } 00332 m_configureEmail->setEnabled(false); 00333 } 00334 00335 void KBugReport::slotSetFrom() 00336 { 00337 delete m_process; 00338 m_process = 0; 00339 m_configureEmail->setEnabled(true); 00340 00341 // ### KDE4: why oh why is KEmailSettings in tdeio? 00342 TDEConfig emailConf( TQString::fromLatin1("emaildefaults") ); 00343 00344 // find out the default profile 00345 emailConf.setGroup( TQString::fromLatin1("Defaults") ); 00346 TQString profile = TQString::fromLatin1("PROFILE_"); 00347 profile += emailConf.readEntry( TQString::fromLatin1("Profile"), 00348 TQString::fromLatin1("Default") ); 00349 00350 emailConf.setGroup( profile ); 00351 TQString fromaddr = emailConf.readEntry( TQString::fromLatin1("EmailAddress") ); 00352 if (fromaddr.isEmpty()) { 00353 struct passwd *p; 00354 p = getpwuid(getuid()); 00355 fromaddr = TQString::fromLatin1(p->pw_name); 00356 } else { 00357 TQString name = emailConf.readEntry( TQString::fromLatin1("FullName")); 00358 if (!name.isEmpty()) 00359 fromaddr = name + TQString::fromLatin1(" <") + fromaddr + TQString::fromLatin1(">"); 00360 } 00361 m_from->setText( fromaddr ); 00362 } 00363 00364 void KBugReport::slotUrlClicked(const TQString &urlText) 00365 { 00366 if ( kapp ) 00367 kapp->invokeBrowser( urlText ); 00368 00369 // When using the web form, a click can also close the window, as there's 00370 // not much to do. It also gives the user a direct response to his click: 00371 if ( d->submitBugButton ) 00372 KDialogBase::slotCancel(); 00373 } 00374 00375 00376 void KBugReport::slotOk( void ) 00377 { 00378 if ( d->submitBugButton ) { 00379 if ( kapp ) 00380 kapp->invokeBrowser( d->url.url() ); 00381 return; 00382 } 00383 00384 if( m_lineedit->text().isEmpty() || 00385 m_subject->text().isEmpty() ) 00386 { 00387 TQString msg = i18n("You must specify both a subject and a description " 00388 "before the report can be sent."); 00389 KMessageBox::error(this,msg); 00390 return; 00391 } 00392 00393 switch ( m_bgSeverity->id( m_bgSeverity->selected() ) ) 00394 { 00395 case 0: // critical 00396 if ( KMessageBox::questionYesNo( this, i18n( 00397 "<p>You chose the severity <b>Critical</b>. " 00398 "Please note that this severity is intended only for bugs that</p>" 00399 "<ul><li>break unrelated software on the system (or the whole system)</li>" 00400 "<li>cause serious data loss</li>" 00401 "<li>introduce a security hole on the system where the affected package is installed</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>" ),TQString::null,KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No ) 00404 return; 00405 break; 00406 case 1: // grave 00407 if ( KMessageBox::questionYesNo( this, i18n( 00408 "<p>You chose the severity <b>Grave</b>. " 00409 "Please note that this severity is intended only for bugs that</p>" 00410 "<ul><li>make the package in question unusable or mostly so</li>" 00411 "<li>cause data loss</li>" 00412 "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n" 00413 "<p>Does the bug you are reporting cause any of the above damage? " 00414 "If it does not, please select a lower severity. Thank you!</p>" ),TQString::null,KStdGuiItem::cont(),KStdGuiItem::cancel() ) == KMessageBox::No ) 00415 return; 00416 break; 00417 } 00418 if( !sendBugReport() ) 00419 { 00420 TQString msg = i18n("Unable to send the bug report.\n" 00421 "Please submit a bug report manually...\n" 00422 "See http://bugs.trinitydesktop.org/ for instructions."); 00423 KMessageBox::error(this, msg + "\n\n" + d->lastError); 00424 return; 00425 } 00426 00427 KMessageBox::information(this, 00428 i18n("Bug report sent, thank you for your input.")); 00429 accept(); 00430 } 00431 00432 void KBugReport::slotCancel() 00433 { 00434 if( !d->submitBugButton && ( m_lineedit->edited() || m_subject->edited() ) ) 00435 { 00436 int rc = KMessageBox::warningYesNo( this, 00437 i18n( "Close and discard\nedited message?" ), 00438 i18n( "Close Message" ), KStdGuiItem::discard(), KStdGuiItem::cont() ); 00439 if( rc == KMessageBox::No ) 00440 return; 00441 } 00442 KDialogBase::slotCancel(); 00443 } 00444 00445 00446 TQString KBugReport::text() const 00447 { 00448 kdDebug() << m_bgSeverity->selected()->name() << endl; 00449 // Prepend the pseudo-headers to the contents of the mail 00450 TQString severity = TQString::fromLatin1(m_bgSeverity->selected()->name()); 00451 TQString appname = d->appcombo->currentText(); 00452 TQString os = TQString::fromLatin1("OS: %1 (%2)\n"). 00453 arg(KDE_COMPILING_OS). 00454 arg(KDE_DISTRIBUTION_TEXT); 00455 TQString bodyText; 00456 for(int i = 0; i < m_lineedit->numLines(); i++) 00457 { 00458 TQString line = m_lineedit->textLine(i); 00459 if (!line.endsWith("\n")) 00460 line += '\n'; 00461 bodyText += line; 00462 } 00463 00464 if (severity == TQString::fromLatin1("i18n") && TDEGlobal::locale()->language() != TDELocale::defaultLanguage()) { 00465 // Case 1 : i18n bug 00466 TQString package = TQString::fromLatin1("i18n_%1").arg(TDEGlobal::locale()->language()); 00467 package = package.replace(TQString::fromLatin1("_"), TQString::fromLatin1("-")); 00468 return TQString::fromLatin1("Package: %1").arg(package) + 00469 TQString::fromLatin1("\n" 00470 "Application: %1\n" 00471 // not really i18n's version, so better here IMHO 00472 "Version: %2\n").arg(appname).arg(m_strVersion)+ 00473 os+TQString::fromLatin1("\n")+bodyText; 00474 } else { 00475 appname = appname.replace(TQString::fromLatin1("_"), TQString::fromLatin1("-")); 00476 // Case 2 : normal bug 00477 return TQString::fromLatin1("Package: %1\n" 00478 "Version: %2\n" 00479 "Severity: %3\n") 00480 .arg(appname).arg(m_strVersion).arg(severity)+ 00481 TQString::fromLatin1("Compiler: %1\n").arg(KDE_COMPILER_VERSION)+ 00482 os+TQString::fromLatin1("\n")+bodyText; 00483 } 00484 } 00485 00486 bool KBugReport::sendBugReport() 00487 { 00488 TQString recipient ( m_aboutData ? 00489 m_aboutData->bugAddress() : 00490 TQString::fromLatin1("submit@bugs.trinitydesktop.org") ); 00491 00492 TQString command; 00493 command = locate("exe", "tdesendbugmail"); 00494 if (command.isEmpty()) 00495 command = TDEStandardDirs::findExe( TQString::fromLatin1("tdesendbugmail") ); 00496 00497 KTempFile outputfile; 00498 outputfile.close(); 00499 00500 TQString subject = m_subject->text(); 00501 command += " --subject "; 00502 command += TDEProcess::quote(subject); 00503 command += " --recipient "; 00504 command += TDEProcess::quote(recipient); 00505 command += " > "; 00506 command += TDEProcess::quote(outputfile.name()); 00507 00508 fflush(stdin); 00509 fflush(stderr); 00510 00511 FILE * fd = popen(TQFile::encodeName(command), "w"); 00512 if (!fd) 00513 { 00514 kdError() << "Unable to open a pipe to " << command << endl; 00515 return false; 00516 } 00517 00518 TQString btext = text(); 00519 fwrite(btext.ascii(),btext.length(),1,fd); 00520 fflush(fd); 00521 00522 int error = pclose(fd); 00523 kdDebug() << "exit status1 " << error << " " << (WIFEXITED(error)) << " " << WEXITSTATUS(error) << endl; 00524 00525 if ((WIFEXITED(error)) && WEXITSTATUS(error) == 1) { 00526 TQFile of(outputfile.name()); 00527 if (of.open(IO_ReadOnly )) { 00528 TQTextStream is(&of); 00529 is.setEncoding(TQTextStream::UnicodeUTF8); 00530 TQString line; 00531 while (!is.eof()) 00532 line = is.readLine(); 00533 d->lastError = line; 00534 } else { 00535 d->lastError = TQString::null; 00536 } 00537 outputfile.unlink(); 00538 return false; 00539 } 00540 outputfile.unlink(); 00541 return true; 00542 } 00543 00544 TQString KBugReport::compilerVersion() { 00545 return KDE_COMPILER_VERSION; 00546 } 00547 00548 TQString KBugReport::operatingSystem() { 00549 return d->os; 00550 } 00551 00552 TQString KBugReport::tdeVersion() { 00553 return d->tde_version; 00554 } 00555 00556 void KBugReport::virtual_hook( int id, void* data ) 00557 { KDialogBase::virtual_hook( id, data ); } 00558 00559 #include "kbugreport.moc"