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 | |
61 | DrKonqi::DrKonqi() |
62 | { |
63 | m_backend = new KCrashBackend(); |
64 | m_systemInformation = new SystemInformation(); |
65 | } |
66 | |
67 | DrKonqi::~DrKonqi() |
68 | { |
69 | delete m_systemInformation; |
70 | delete m_backend; |
71 | } |
72 | |
73 | //static |
74 | DrKonqi *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 |
84 | class EnableCrashCatchingDelayed : public QObject |
85 | { |
86 | public: |
87 | EnableCrashCatchingDelayed() { |
88 | startTimer(10000); // 10 s |
89 | } |
90 | protected: |
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 | |
99 | bool 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 | |
118 | void DrKonqi::cleanup() |
119 | { |
120 | delete instance(); |
121 | } |
122 | |
123 | //static |
124 | SystemInformation *DrKonqi::systemInformation() |
125 | { |
126 | return instance()->m_systemInformation; |
127 | } |
128 | |
129 | //static |
130 | DebuggerManager* DrKonqi::debuggerManager() |
131 | { |
132 | return instance()->m_backend->debuggerManager(); |
133 | } |
134 | |
135 | //static |
136 | CrashedApplication *DrKonqi::crashedApplication() |
137 | { |
138 | return instance()->m_backend->crashedApplication(); |
139 | } |
140 | |
141 | //static |
142 | void 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 | |