1/*
2 Copyright (C) 2009 George Kiagiadakis <gkiagia@users.sourceforge.net>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 Parts of this code were originally under the following license:
18
19 * Copyright (C) 2000-2003 Hans Petter Bieker <bieker@kde.org>
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 *
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 *
31 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
32 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
34 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41*/
42#include "drkonqi.h"
43
44#include <QtCore/QWeakPointer>
45#include <QtCore/QTextStream>
46#include <QtCore/QTimerEvent>
47
48#include <KMessageBox>
49#include <KFileDialog>
50#include <KTemporaryFile>
51#include <KCmdLineArgs>
52#include <KIO/NetAccess>
53#include <KCrash>
54#include <KDebug>
55#include <KLocalizedString>
56
57#include "systeminformation.h"
58#include "crashedapplication.h"
59#include "drkonqibackends.h"
60
61DrKonqi::DrKonqi()
62{
63 m_backend = new KCrashBackend();
64 m_systemInformation = new SystemInformation();
65}
66
67DrKonqi::~DrKonqi()
68{
69 delete m_systemInformation;
70 delete m_backend;
71}
72
73//static
74DrKonqi *DrKonqi::instance()
75{
76 static DrKonqi *drKonqiInstance = NULL;
77 if (!drKonqiInstance) {
78 drKonqiInstance = new DrKonqi();
79 }
80 return drKonqiInstance;
81}
82
83//based on KCrashDelaySetHandler from kdeui/util/kcrash.cpp
84class EnableCrashCatchingDelayed : public QObject
85{
86public:
87 EnableCrashCatchingDelayed() {
88 startTimer(10000); // 10 s
89 }
90protected:
91 void timerEvent(QTimerEvent *event) {
92 kDebug() << "Enabling drkonqi crash catching";
93 KCrash::setDrKonqiEnabled(true);
94 killTimer(event->timerId());
95 this->deleteLater();
96 }
97};
98
99bool DrKonqi::init()
100{
101 if (!instance()->m_backend->init()) {
102 cleanup();
103 return false;
104 } else { //all ok, continue initialization
105 // Set drkonqi to handle its own crashes, but only if the crashed app
106 // is not drkonqi already. If it is drkonqi, delay enabling crash catching
107 // to prevent recursive crashes (in case it crashes at startup)
108 if (crashedApplication()->fakeExecutableBaseName() != "drkonqi") {
109 kDebug() << "Enabling drkonqi crash catching";
110 KCrash::setDrKonqiEnabled(true);
111 } else {
112 new EnableCrashCatchingDelayed;
113 }
114 return true;
115 }
116}
117
118void DrKonqi::cleanup()
119{
120 delete instance();
121}
122
123//static
124SystemInformation *DrKonqi::systemInformation()
125{
126 return instance()->m_systemInformation;
127}
128
129//static
130DebuggerManager* DrKonqi::debuggerManager()
131{
132 return instance()->m_backend->debuggerManager();
133}
134
135//static
136CrashedApplication *DrKonqi::crashedApplication()
137{
138 return instance()->m_backend->crashedApplication();
139}
140
141//static
142void DrKonqi::saveReport(const QString & reportText, QWidget *parent)
143{
144 if (KCmdLineArgs::parsedArgs()->isSet("safer")) {
145 KTemporaryFile tf;
146 tf.setSuffix(".kcrash.txt");
147 tf.setAutoRemove(false);
148
149 if (tf.open()) {
150 QTextStream textStream(&tf);
151 textStream << reportText;
152 textStream.flush();
153 KMessageBox::information(parent, i18nc("@info",
154 "Report saved to <filename>%1</filename>.",
155 tf.fileName()));
156 } else {
157 KMessageBox::sorry(parent, i18nc("@info","Could not create a file in which to save the report."));
158 }
159 } else {
160 QString defname = getSuggestedKCrashFilename(crashedApplication());
161
162 QWeakPointer<KFileDialog> dlg = new KFileDialog(defname, QString(), parent);
163 dlg.data()->setSelection(defname);
164 dlg.data()->setCaption(i18nc("@title:window","Select Filename"));
165 dlg.data()->setOperationMode(KFileDialog::Saving);
166 dlg.data()->setMode(KFile::File);
167 dlg.data()->setConfirmOverwrite(true);
168 dlg.data()->exec();
169
170 if (dlg.isNull()) {
171 //Dialog is invalid, it was probably deleted (ex. via DBus call)
172 //return and do not crash
173 return;
174 }
175
176 KUrl fileUrl = dlg.data()->selectedUrl();
177 delete dlg.data();
178
179 if (fileUrl.isValid()) {
180 KTemporaryFile tf;
181 if (tf.open()) {
182 QTextStream ts(&tf);
183 ts << reportText;
184 ts.flush();
185 } else {
186 KMessageBox::sorry(parent, i18nc("@info","Cannot open file <filename>%1</filename> "
187 "for writing.", tf.fileName()));
188 return;
189 }
190
191 if (!KIO::NetAccess::upload(tf.fileName(), fileUrl, parent)) {
192 KMessageBox::sorry(parent, KIO::NetAccess::lastErrorString());
193 }
194 }
195 }
196}
197
198