File indexing completed on 2024-04-21 15:05:47

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "kbugreport.h"
0009 
0010 #include <QCloseEvent>
0011 #include <QDesktopServices>
0012 #include <QDialogButtonBox>
0013 #include <QFile>
0014 #include <QGridLayout>
0015 #include <QGroupBox>
0016 #include <QHBoxLayout>
0017 #include <QLabel>
0018 #include <QLineEdit>
0019 #include <QLocale>
0020 #include <QProcess>
0021 #include <QPushButton>
0022 #include <QRadioButton>
0023 #include <QStandardPaths>
0024 #include <QTextEdit>
0025 #include <QUrl>
0026 #include <QUrlQuery>
0027 
0028 #include <KAboutData>
0029 #include <KConfig>
0030 #include <KEMailSettings>
0031 #include <KLocalizedString>
0032 #include <KMessageBox>
0033 #include <KMessageDialog>
0034 #include <KTitleWidget>
0035 
0036 #include "../kxmlgui_version.h"
0037 #include "config-xmlgui.h"
0038 #include "debug.h"
0039 #include "systeminformation_p.h"
0040 
0041 #include <array>
0042 
0043 class KBugReportPrivate
0044 {
0045 public:
0046     KBugReportPrivate(KBugReport *qq)
0047         : q(qq)
0048         , m_aboutData(KAboutData::applicationData())
0049     {
0050     }
0051 
0052     enum BugDestination {
0053         BugsKdeOrg,
0054         CustomEmail,
0055         CustomUrl,
0056     };
0057 
0058     // Calls kcmshell5 System/email
0059     void slotConfigureEmail();
0060 
0061     // Sets the "From" field from the e-mail configuration.
0062     // Called at creation time, but also after "Configure email" is closed.
0063     void slotSetFrom();
0064 
0065     // Update the url to match the current OS, selected app, etc
0066     void updateUrl();
0067 
0068     KBugReport *const q;
0069     QProcess *m_process = nullptr;
0070     KAboutData m_aboutData;
0071 
0072     QTextEdit *m_lineedit = nullptr;
0073     QLineEdit *m_subject = nullptr;
0074     QLabel *m_from = nullptr;
0075     QLabel *m_version = nullptr;
0076     QString m_strVersion;
0077     QGroupBox *m_bgSeverity = nullptr;
0078     QPushButton *m_configureEmail = nullptr;
0079 
0080     QString lastError;
0081     QString kde_version;
0082     QString appname;
0083     QString os;
0084     QUrl url;
0085     QList<QRadioButton *> severityButtons;
0086     int currentSeverity() const
0087     {
0088         for (int i = 0; i < severityButtons.count(); i++) {
0089             if (severityButtons[i]->isChecked()) {
0090                 return i;
0091             }
0092         }
0093         return -1;
0094     }
0095     BugDestination bugDestination;
0096 };
0097 
0098 KBugReport::KBugReport(const KAboutData &aboutData, QWidget *_parent)
0099     : QDialog(_parent)
0100     , d(new KBugReportPrivate(this))
0101 {
0102     setWindowTitle(i18nc("@title:window", "Submit Bug Report"));
0103 
0104     QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
0105     buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0106     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0107     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0108 
0109     d->m_aboutData = aboutData;
0110     d->m_process = nullptr;
0111     d->bugDestination = KBugReportPrivate::CustomEmail;
0112 
0113     const QString bugAddress = d->m_aboutData.bugAddress();
0114     if (bugAddress == QLatin1String("submit@bugs.kde.org")) {
0115         // This is a core KDE application -> redirect to the web form
0116         d->bugDestination = KBugReportPrivate::BugsKdeOrg;
0117     } else if (!QUrl(bugAddress).scheme().isEmpty()) {
0118         // The bug reporting address is a URL -> redirect to that
0119         d->bugDestination = KBugReportPrivate::CustomUrl;
0120     }
0121 
0122     if (d->bugDestination != KBugReportPrivate::CustomEmail) {
0123         KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::close());
0124     }
0125 
0126     QLabel *tmpLabel;
0127     QVBoxLayout *lay = new QVBoxLayout(this);
0128 
0129     KTitleWidget *title = new KTitleWidget(this);
0130     title->setText(i18n("Submit Bug Report"));
0131     title->setIconSize(QSize(32, 32));
0132     title->setIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug")));
0133     lay->addWidget(title);
0134 
0135     QGridLayout *glay = new QGridLayout();
0136     lay->addLayout(glay);
0137 
0138     int row = 0;
0139 
0140     if (d->bugDestination == KBugReportPrivate::CustomEmail) {
0141         // From
0142         QString qwtstr = i18n("Your email address. If incorrect, use the Configure Email button to change it");
0143         tmpLabel = new QLabel(i18nc("Email sender address", "From:"), this);
0144         glay->addWidget(tmpLabel, row, 0);
0145         tmpLabel->setWhatsThis(qwtstr);
0146         d->m_from = new QLabel(this);
0147         glay->addWidget(d->m_from, row, 1);
0148         d->m_from->setWhatsThis(qwtstr);
0149 
0150         // Configure email button
0151         d->m_configureEmail = new QPushButton(i18nc("@action:button", "Configure Email..."), this);
0152         connect(d->m_configureEmail, &QPushButton::clicked, this, [this]() {
0153             d->slotConfigureEmail();
0154         });
0155         glay->addWidget(d->m_configureEmail, 0, 2, 3, 1, Qt::AlignTop | Qt::AlignRight);
0156 
0157         // To
0158         qwtstr = i18n("The email address this bug report is sent to.");
0159         tmpLabel = new QLabel(i18nc("Email receiver address", "To:"), this);
0160         glay->addWidget(tmpLabel, ++row, 0);
0161         tmpLabel->setWhatsThis(qwtstr);
0162         tmpLabel = new QLabel(d->m_aboutData.bugAddress(), this);
0163         tmpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0164         glay->addWidget(tmpLabel, row, 1);
0165         tmpLabel->setWhatsThis(qwtstr);
0166 
0167         KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok),
0168                          KGuiItem(i18nc("@action:button", "&Send"),
0169                                   QStringLiteral("mail-send"),
0170                                   i18nc("@info:tooltip", "Send bug report."),
0171                                   i18nc("@info:whatsthis", "Send this bug report to %1.", d->m_aboutData.bugAddress())));
0172         row++;
0173     } else {
0174         d->m_configureEmail = nullptr;
0175         d->m_from = nullptr;
0176     }
0177 
0178     // Program name
0179     QString qwtstr =
0180         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");
0181     tmpLabel = new QLabel(i18n("Application: "), this);
0182     glay->addWidget(tmpLabel, row, 0);
0183     tmpLabel->setWhatsThis(qwtstr);
0184     QLabel *appLabel = new QLabel(this);
0185     d->appname = d->m_aboutData.productName();
0186     appLabel->setText(d->appname);
0187     glay->addWidget(appLabel, row, 1);
0188     tmpLabel->setWhatsThis(qwtstr);
0189 
0190     // Version
0191     qwtstr = i18n("The version of this application - please make sure that no newer version is available before sending a bug report");
0192     tmpLabel = new QLabel(i18n("Version:"), this);
0193     glay->addWidget(tmpLabel, ++row, 0);
0194     tmpLabel->setWhatsThis(qwtstr);
0195     d->m_strVersion = d->m_aboutData.version();
0196     if (d->m_strVersion.isEmpty()) {
0197         d->m_strVersion = i18n("no version set (programmer error)");
0198     }
0199     d->kde_version = QStringLiteral(KXMLGUI_VERSION_STRING) + QLatin1String(", ") + QStringLiteral(XMLGUI_DISTRIBUTION_TEXT);
0200     if (d->bugDestination != KBugReportPrivate::BugsKdeOrg) {
0201         d->m_strVersion += QLatin1Char(' ') + d->kde_version;
0202     }
0203     d->m_version = new QLabel(d->m_strVersion, this);
0204     d->m_version->setTextInteractionFlags(Qt::TextBrowserInteraction);
0205     // glay->addWidget( d->m_version, row, 1 );
0206     glay->addWidget(d->m_version, row, 1, 1, 2);
0207     d->m_version->setWhatsThis(qwtstr);
0208 
0209     tmpLabel = new QLabel(i18n("OS:"), this);
0210     glay->addWidget(tmpLabel, ++row, 0);
0211 
0212 #ifdef Q_OS_WINDOWS
0213     d->os = i18nc("%1 is the operating system name, e.g. 'Windows 10', %2 is the CPU architecture, e.g. 'x86_64'",
0214                   "%1 (%2)",
0215                   QSysInfo::prettyProductName(),
0216                   QSysInfo::currentCpuArchitecture());
0217 #else
0218     if (QSysInfo::productVersion() != QLatin1String("unknown")) {
0219         d->os = i18nc(
0220             "%1 is the operating system name, e.g. 'Fedora Linux', %2 is the operating system version, e.g. '35', %3 is the CPU architecture, e.g. 'x86_64'",
0221             "%1 %2 (%3)",
0222             QSysInfo::prettyProductName(),
0223             QSysInfo::productVersion(),
0224             QSysInfo::currentCpuArchitecture());
0225     } else {
0226         d->os = i18nc("%1 is the operating system name, e.g. 'Fedora Linux', %2 is the CPU architecture, e.g. 'x86_64'",
0227                       "%1 (%2)",
0228                       QSysInfo::prettyProductName(),
0229                       QSysInfo::currentCpuArchitecture());
0230     }
0231 #endif
0232 
0233     tmpLabel = new QLabel(d->os, this);
0234     tmpLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
0235     glay->addWidget(tmpLabel, row, 1, 1, 2);
0236 
0237     if (d->bugDestination == KBugReportPrivate::CustomEmail) {
0238         // Severity
0239         d->m_bgSeverity = new QGroupBox(i18nc("@title:group", "Se&verity"), this);
0240 
0241         struct SeverityData {
0242             QString name;
0243             QString text;
0244         };
0245         const std::array<SeverityData, 5> severityData = {{
0246             {QStringLiteral("critical"), i18nc("bug severity", "Critical")},
0247             {QStringLiteral("grave"), i18nc("bug severity", "Grave")},
0248             {QStringLiteral("normal"), i18nc("bug severity", "Normal")},
0249             {QStringLiteral("wishlist"), i18nc("bug severity", "Wishlist")},
0250             {QStringLiteral("i18n"), i18nc("bug severity", "Translation")},
0251         }};
0252 
0253         QHBoxLayout *severityLayout = new QHBoxLayout(d->m_bgSeverity);
0254         for (auto &severityDatum : severityData) {
0255             // Store the severity string as the name
0256             QRadioButton *rb = new QRadioButton(severityDatum.text, d->m_bgSeverity);
0257             rb->setObjectName(severityDatum.name);
0258             d->severityButtons.append(rb);
0259             severityLayout->addWidget(rb);
0260         }
0261         d->severityButtons[2]->setChecked(true); // default : "normal"
0262 
0263         lay->addWidget(d->m_bgSeverity);
0264 
0265         // Subject
0266         QHBoxLayout *hlay = new QHBoxLayout();
0267         lay->addItem(hlay);
0268         tmpLabel = new QLabel(i18n("S&ubject: "), this);
0269         hlay->addWidget(tmpLabel);
0270         d->m_subject = new QLineEdit(this);
0271         d->m_subject->setClearButtonEnabled(true);
0272         d->m_subject->setFocus();
0273         tmpLabel->setBuddy(d->m_subject);
0274         hlay->addWidget(d->m_subject);
0275 
0276         QString text = i18n(
0277             "Enter the text (in English if possible) that you wish to submit for the "
0278             "bug report.\n"
0279             "If you press \"Send\", a mail message will be sent to the maintainer of "
0280             "this program.\n");
0281         QLabel *label = new QLabel(this);
0282 
0283         label->setText(text);
0284         lay->addWidget(label);
0285 
0286         // The multiline-edit
0287         d->m_lineedit = new QTextEdit(this);
0288         d->m_lineedit->setMinimumHeight(180); // make it big
0289         d->m_lineedit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
0290         d->m_lineedit->setLineWrapMode(QTextEdit::WidgetWidth);
0291         lay->addWidget(d->m_lineedit, 10 /*stretch*/);
0292 
0293         d->slotSetFrom();
0294     } else {
0295         // Point to the web form
0296 
0297         QString text;
0298         if (d->bugDestination == KBugReportPrivate::BugsKdeOrg) {
0299             text = i18n(
0300                 "<qt>To submit a bug report, click on the button below. This will open a web browser "
0301                 "window on <a href=\"https://bugs.kde.org\">https://bugs.kde.org</a> where you will find "
0302                 "a form to fill in. The information displayed above will be transferred to that server.</qt>");
0303             d->updateUrl();
0304         } else {
0305             text = i18n(
0306                 "<qt>To submit a bug report, click on the button below. This will open a web browser "
0307                 "window on <a href=\"%1\">%2</a>.</qt>",
0308                 bugAddress,
0309                 bugAddress);
0310             d->url = QUrl(bugAddress);
0311         }
0312 
0313         lay->addSpacing(10);
0314         QLabel *label = new QLabel(text, this);
0315         label->setOpenExternalLinks(true);
0316         label->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard);
0317         label->setWordWrap(true);
0318         lay->addWidget(label);
0319         lay->addSpacing(10);
0320 
0321         QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0322         if (d->bugDestination == KBugReportPrivate::BugsKdeOrg) {
0323             okButton->setText(i18nc("@action:button", "&Launch Bug Report Wizard"));
0324         } else {
0325             okButton->setText(i18nc("@action:button", "&Submit Bug Report"));
0326         }
0327         okButton->setIcon(QIcon::fromTheme(QStringLiteral("tools-report-bug")));
0328     }
0329 
0330     lay->addWidget(buttonBox);
0331     setMinimumHeight(sizeHint().height() + 20); // WORKAROUND: prevent "cropped" qcombobox
0332 }
0333 
0334 KBugReport::~KBugReport() = default;
0335 
0336 QString KBugReport::messageBody() const
0337 {
0338     if (d->bugDestination == KBugReportPrivate::CustomEmail) {
0339         return d->m_lineedit->toPlainText();
0340     } else {
0341         return QString();
0342     }
0343 }
0344 
0345 void KBugReport::setMessageBody(const QString &messageBody)
0346 {
0347     if (d->bugDestination == KBugReportPrivate::CustomEmail) {
0348         d->m_lineedit->setPlainText(messageBody);
0349     }
0350 }
0351 
0352 void KBugReportPrivate::updateUrl()
0353 {
0354     url = QUrl(QStringLiteral("https://bugs.kde.org/enter_bug.cgi"));
0355     QUrlQuery query;
0356     query.addQueryItem(QStringLiteral("format"), QStringLiteral("guided")); // use the guided form
0357 
0358     // the string format is product/component, where component is optional
0359     QStringList list = appname.split(QLatin1Char('/'));
0360     query.addQueryItem(QStringLiteral("product"), list[0]);
0361     if (list.size() == 2) {
0362         query.addQueryItem(QStringLiteral("component"), list[1]);
0363     }
0364 
0365     query.addQueryItem(QStringLiteral("version"), m_strVersion);
0366     url.setQuery(query);
0367 
0368     // TODO: guess and fill OS(sys_os) and Platform(rep_platform) fields
0369 }
0370 
0371 void KBugReportPrivate::slotConfigureEmail()
0372 {
0373     if (m_process) {
0374         return;
0375     }
0376 
0377     const QString exec = QStandardPaths::findExecutable(QStringLiteral("kcmshell5"));
0378     if (exec.isEmpty()) {
0379         const QString msg = i18nc("The second arg is 'kde-cli-tools' which is the package that contains kcmshell5 (the first arg)",
0380                                   "Could not find <application>%1</application> executable (usually it's part of the \"%2\" package).",
0381                                   QStringLiteral("kcmshell5"),
0382                                   QStringLiteral("kde-cli-tools"));
0383         auto *dlg = new KMessageDialog(KMessageDialog::Error, msg, q);
0384         dlg->setAttribute(Qt::WA_DeleteOnClose);
0385         dlg->setModal(true);
0386         dlg->show();
0387         return;
0388     }
0389 
0390     m_process = new QProcess;
0391     QObject::connect(m_process, &QProcess::finished, q, [this]() {
0392         slotSetFrom();
0393     });
0394     m_process->start(exec, QStringList{QStringLiteral("kcm_users")});
0395     if (!m_process->waitForStarted()) {
0396         // qCDebug(DEBUG_KXMLGUI) << "Couldn't start kcmshell5..";
0397         delete m_process;
0398         m_process = nullptr;
0399         return;
0400     }
0401     m_configureEmail->setEnabled(false);
0402 }
0403 
0404 void KBugReportPrivate::slotSetFrom()
0405 {
0406     delete m_process;
0407     m_process = nullptr;
0408     m_configureEmail->setEnabled(true);
0409 
0410     KEMailSettings emailSettings;
0411     QString fromaddr = emailSettings.getSetting(KEMailSettings::EmailAddress);
0412     if (fromaddr.isEmpty()) {
0413         fromaddr = SystemInformation::userName();
0414     } else {
0415         QString name = emailSettings.getSetting(KEMailSettings::RealName);
0416         if (!name.isEmpty()) {
0417             fromaddr = name + QLatin1String(" <") + fromaddr + QLatin1Char('>');
0418         }
0419     }
0420     m_from->setText(fromaddr);
0421 }
0422 
0423 void KBugReport::accept()
0424 {
0425     if (d->bugDestination != KBugReportPrivate::CustomEmail) {
0426         QDesktopServices::openUrl(d->url);
0427         return;
0428     }
0429 
0430     if (d->m_lineedit->toPlainText().isEmpty() || d->m_subject->text().isEmpty()) {
0431         QString msg = i18n(
0432             "You must specify both a subject and a description "
0433             "before the report can be sent.");
0434         KMessageBox::error(this, msg);
0435         return;
0436     }
0437 
0438     switch (d->currentSeverity()) {
0439     case 0: // critical
0440         if (KMessageBox::questionTwoActions(this,
0441                                             i18n("<p>You chose the severity <b>Critical</b>. "
0442                                                  "Please note that this severity is intended only for bugs that:</p>"
0443                                                  "<ul><li>break unrelated software on the system (or the whole system)</li>"
0444                                                  "<li>cause serious data loss</li>"
0445                                                  "<li>introduce a security hole on the system where the affected package is installed</li></ul>\n"
0446                                                  "<p>Does the bug you are reporting cause any of the above damage? "
0447                                                  "If it does not, please select a lower severity. Thank you.</p>"),
0448                                             QString(),
0449                                             KStandardGuiItem::cont(),
0450                                             KStandardGuiItem::cancel())
0451             == KMessageBox::SecondaryAction) {
0452             return;
0453         }
0454         break;
0455     case 1: // grave
0456         if (KMessageBox::questionTwoActions(
0457                 this,
0458                 i18n("<p>You chose the severity <b>Grave</b>. "
0459                      "Please note that this severity is intended only for bugs that:</p>"
0460                      "<ul><li>make the package in question unusable or mostly so</li>"
0461                      "<li>cause data loss</li>"
0462                      "<li>introduce a security hole allowing access to the accounts of users who use the affected package</li></ul>\n"
0463                      "<p>Does the bug you are reporting cause any of the above damage? "
0464                      "If it does not, please select a lower severity. Thank you.</p>"),
0465                 QString(),
0466                 KStandardGuiItem::cont(),
0467                 KStandardGuiItem::cancel())
0468             == KMessageBox::SecondaryAction) {
0469             return;
0470         }
0471         break;
0472     default:
0473         break;
0474     }
0475     if (!sendBugReport()) {
0476         QString msg = i18n(
0477             "Unable to send the bug report.\n"
0478             "Please submit a bug report manually....\n"
0479             "See https://bugs.kde.org/ for instructions.");
0480         KMessageBox::error(this, msg + QLatin1String("\n\n") + d->lastError);
0481         return;
0482     }
0483 
0484     KMessageBox::information(this, i18n("Bug report sent, thank you for your input."));
0485     QDialog::accept();
0486 }
0487 
0488 void KBugReport::closeEvent(QCloseEvent *e)
0489 {
0490     if (d->bugDestination == KBugReportPrivate::CustomEmail && ((d->m_lineedit->toPlainText().length() > 0) || d->m_subject->isModified())) {
0491         int rc = KMessageBox::warningTwoActions(this,
0492                                                 i18n("Close and discard\nedited message?"),
0493                                                 i18nc("@title:window", "Close Message"),
0494                                                 KStandardGuiItem::discard(),
0495                                                 KStandardGuiItem::cont());
0496         if (rc == KMessageBox::SecondaryAction) {
0497             e->ignore();
0498             return;
0499         }
0500     }
0501     QDialog::closeEvent(e);
0502 }
0503 
0504 QString KBugReport::text() const
0505 {
0506     // qCDebug(DEBUG_KXMLGUI) << d->severityButtons[d->currentSeverity()]->objectName();
0507     // Prepend the pseudo-headers to the contents of the mail
0508     QString severity = d->severityButtons[d->currentSeverity()]->objectName();
0509     QString appname = d->appname;
0510     QString os = QStringLiteral("OS: %1 (%2)\n").arg(QStringLiteral(XMLGUI_COMPILING_OS), QStringLiteral(XMLGUI_DISTRIBUTION_TEXT));
0511     QString bodyText;
0512     /*  for(int i = 0; i < m_lineedit->numLines(); i++)
0513       {
0514          QString line = m_lineedit->textLine(i);
0515          if (!line.endsWith("\n"))
0516             line += '\n';
0517          bodyText += line;
0518       }
0519     */
0520     bodyText = d->m_lineedit->toPlainText();
0521     if (bodyText.length() > 0) {
0522         if (bodyText[bodyText.length() - 1] != QLatin1Char('\n')) {
0523             bodyText += QLatin1Char('\n');
0524         }
0525     }
0526     if (severity == QLatin1String("i18n") && QLocale().language() != QLocale::system().language()) {
0527         // Case 1 : i18n bug
0528         QString package = QLatin1String("i18n_") + QLocale::languageToString(QLocale().language());
0529         package.replace(QLatin1Char('_'), QLatin1Char('-'));
0530         /* clang-format off */
0531         return QLatin1String("Package: ") + package
0532             + QLatin1String("\nApplication: ") + appname
0533             + QLatin1String("\nVersion: ") + d->m_strVersion // not really i18n's version, so better here IMHO
0534             + QLatin1Char('\n') + os
0535             + QLatin1Char('\n') + bodyText;
0536         /* clang-format on */
0537     } else {
0538         appname.replace(QLatin1Char('_'), QLatin1Char('-'));
0539         // Case 2 : normal bug
0540         /* clang-format off */
0541         return QLatin1String("Package: ") + appname
0542             + QLatin1String("\nVersion: ") + d->m_strVersion
0543             + QLatin1String("\nSeverity: ") + severity
0544             + QLatin1Char('\n') + os
0545             + QLatin1Char('\n') + bodyText;
0546         /* clang-format on */
0547     }
0548 }
0549 
0550 bool KBugReport::sendBugReport()
0551 {
0552     QString recipient = d->m_aboutData.bugAddress();
0553     if (recipient.isEmpty()) {
0554         recipient = QStringLiteral("submit@bugs.kde.org");
0555     }
0556 
0557     QString command = QStandardPaths::findExecutable(QStringLiteral("ksendbugmail"));
0558     if (command.isEmpty()) {
0559         command = QFile::decodeName(CMAKE_INSTALL_PREFIX "/" KDE_INSTALL_LIBEXECDIR_KF "/ksendbugmail");
0560     }
0561 
0562     QProcess proc;
0563     QStringList args;
0564     args << QStringLiteral("--subject") << d->m_subject->text() << QStringLiteral("--recipient") << recipient;
0565     proc.start(command, args);
0566     // qCDebug(DEBUG_KXMLGUI) << command << args;
0567     if (!proc.waitForStarted()) {
0568         qCCritical(DEBUG_KXMLGUI) << "Unable to open a pipe to " << command;
0569         return false;
0570     }
0571     proc.write(text().toUtf8());
0572     proc.closeWriteChannel();
0573 
0574     proc.waitForFinished();
0575     // qCDebug(DEBUG_KXMLGUI) << "kbugreport: sendbugmail exit, status " << proc.exitStatus() << " code " << proc.exitCode();
0576 
0577     QByteArray line;
0578     if (proc.exitStatus() == QProcess::NormalExit && proc.exitCode() != 0) {
0579         // XXX not stderr?
0580         while (!proc.atEnd()) {
0581             line = proc.readLine();
0582         }
0583         d->lastError = QString::fromUtf8(line);
0584         return false;
0585     }
0586     return true;
0587 }
0588 
0589 #include "moc_kbugreport.cpp"