summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikola Pajkovsky <npajkovs@redhat.com>2010-01-21 17:55:12 +0100
committerNikola Pajkovsky <npajkovs@redhat.com>2010-01-21 17:55:12 +0100
commit6a332432509a6c7299d212b1bb769cf6dd054758 (patch)
treee935a2b4806f10fbb1b5ae448c7427d304f2c439
parent2afa768308a7f00f0f0d5c4a95f5b20e8c62ef39 (diff)
parent44d7d1e6acb25dc719838560b002514fc51b62c3 (diff)
downloadabrt-6a332432509a6c7299d212b1bb769cf6dd054758.tar.gz
abrt-6a332432509a6c7299d212b1bb769cf6dd054758.tar.xz
abrt-6a332432509a6c7299d212b1bb769cf6dd054758.zip
Merge branch 'master' into hotfix
-rw-r--r--abrt.spec30
-rw-r--r--configure.ac2
-rw-r--r--inc/CrashTypes.h50
-rw-r--r--lib/Plugins/Bugzilla.cpp4
-rw-r--r--lib/Plugins/Catcut.cpp2
-rw-r--r--lib/Plugins/FileTransfer.cpp6
-rw-r--r--lib/Plugins/Mailx.cpp20
-rw-r--r--lib/Plugins/TicketUploader.h1
-rw-r--r--lib/Utils/CrashTypes.cpp83
-rw-r--r--lib/Utils/make_descr.cpp20
-rw-r--r--lib/Utils/test.cpp8
-rw-r--r--po/nl.po199
-rwxr-xr-xscripts/abrt-bz-stats156
-rw-r--r--src/CLI/CLI.cpp18
-rw-r--r--src/CLI/report.cpp12
-rw-r--r--src/Daemon/CommLayerServerDBus.cpp7
-rw-r--r--src/Daemon/CommLayerServerSocket.cpp3
-rw-r--r--src/Daemon/CrashWatcher.cpp13
-rw-r--r--src/Daemon/CrashWatcher.h2
-rw-r--r--src/Daemon/Daemon.cpp14
-rw-r--r--src/Daemon/MiddleWare.cpp273
-rw-r--r--src/Gui/CCDump.py61
-rw-r--r--src/Gui/CCMainWindow.py24
-rw-r--r--src/Gui/CCReporterDialog.py160
-rw-r--r--src/Gui/CC_gui_functions.py11
-rw-r--r--src/Gui/PluginList.py5
26 files changed, 719 insertions, 465 deletions
diff --git a/abrt.spec b/abrt.spec
index e82a7f01..90b59683 100644
--- a/abrt.spec
+++ b/abrt.spec
@@ -3,7 +3,7 @@
%{!?python_sitearch: %define python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
Summary: Automatic bug detection and reporting tool
Name: abrt
-Version: 1.0.3
+Version: 1.0.4
Release: 1%{?dist}
License: GPLv2+
Group: Applications/System
@@ -402,6 +402,34 @@ fi
%defattr(-,root,root,-)
%changelog
+* Wed Jan 20 2010 Jiri Moskovcak <jmoskovc@redhat.com> 1.0.4-1
+- GUI: redesign of reporter dialog (jmoskovc@redhat.com)
+- Set the prgname to "Automatic Bug Reporting Tool" fixes rhbz#550357 (jmoskovc@redhat.com)
+- CCpp analyzer: display __abort_msg in backtrace. closes rhbz#549735 (vda.linux@googlemail.com)
+- s/os.exit/sys.exit - closes rhbz#556313 (vda.linux@googlemail.com)
+- use repr() to print variable values in python hook rhbz#545070 (jmoskovc@redhat.com)
+- gui: add logging infrastructure (vda.linux@googlemail.com)
+- Added "Enabled = yes" to all plugin's config files (jmoskovc@redhat.com)
+- *: disable plugin loading/unloading through GUI. Document keyring a bit (vda.linux@googlemail.com)
+- fix memory leaks in catcut plugin (npajkovs@redhat.com)
+- fix memory leaks in bugzilla (npajkovs@redhat.com)
+- abrt-hook-python: sanitize input more; log to syslog (vda.linux@googlemail.com)
+- Fixed /var/cache/abrt/ permissions (kklic@redhat.com)
+- Kerneloops: we require commandline for every crash, save dummy one for oopses (vda.linux@googlemail.com)
+- *: remove nss dependencies (vda.linux@googlemail.com)
+- CCpp: use our own sha1 implementation (less pain with nss libs) (vda.linux@googlemail.com)
+- DebugDump: more consistent logic in setting mode and uid:gid on dump dir (vda.linux@googlemail.com)
+- fixes based on security review (vda.linux@googlemail.com)
+- SOSreport/TicketUploader: use more restrictive file modes (vda.linux@googlemail.com)
+- abrt-hook-python: add input sanitization and directory size guard (vda.linux@googlemail.com)
+- RunApp: safer chdir. Overhauled "sparn a child and get its output" in general (vda.linux@googlemail.com)
+- DebugDump: use more restrictive modes (vda.linux@googlemail.com)
+- SQLite3: check for SQL injection (vda.linux@googlemail.com)
+- replace plugin enabling via EnabledPlugins by par-plugin Enabled = yes/no (vda.linux@googlemail.com)
+- abrt.spec: move "requires: gdb" to abrt-desktop (vda.linux@googlemail.com)
+- ccpp: add a possibility to disable backtrace generation (vda.linux@googlemail.com)
+- abrtd: limit the number of frames in backtrace to 3000 (vda.linux@googlemail.com)
+
* Tue Jan 5 2010 Jiri Moskovcak <jmoskovc@redhat.com> 1.0.3-1
- speed optimalization of abrt-debuginfo-install (jmoskovc@redhat.com)
- updated credits (jmoskovc@redhat.com)
diff --git a/configure.ac b/configure.ac
index 4f73d07a..6cc65a8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([abrt], [1.0.3], [crash-catcher@fedorahosted.org])
+AC_INIT([abrt], [1.0.4], [crash-catcher@fedorahosted.org])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
diff --git a/inc/CrashTypes.h b/inc/CrashTypes.h
index 9daefa93..b14413d5 100644
--- a/inc/CrashTypes.h
+++ b/inc/CrashTypes.h
@@ -45,21 +45,18 @@
#define FILENAME_MEMORYMAP "memorymap"
#define FILENAME_KERNELOOPS "kerneloops"
+#define CD_DUPHASH "DUPHASH"
#define CD_UUID "UUID"
-#define CD_UID "UID"
+#define CD_DUMPDIR "DumpDir"
#define CD_COUNT "Count"
-#define CD_EXECUTABLE "Executable"
-#define CD_PACKAGE "Package"
-#define CD_DESCRIPTION "Description"
-#define CD_TIME "Time"
#define CD_REPORTED "Reported"
#define CD_MESSAGE "Message"
-#define CD_COMMENT "Comment"
-#define CD_REPRODUCE "How to reproduce"
-#define CD_MWANALYZER "_MWAnalyzer"
-#define CD_MWUID "_MWUID"
-#define CD_MWUUID "_MWUUID"
-#define CD_MWDDD "_MWDDD"
+
+
+// Crash data is a map of 3-element vectors of strings: type, editable, content
+#define CD_TYPE 0
+#define CD_EDITABLE 1
+#define CD_CONTENT 2
// SYS - system value, should not be displayed
// BIN - binary data
@@ -67,34 +64,35 @@
#define CD_SYS "s"
#define CD_BIN "b"
#define CD_TXT "t"
-
-/* Text bigger than this usually is attached, not added inline */
+// Text bigger than this usually is attached, not added inline
#define CD_TEXT_ATT_SIZE (2*1024)
-#define CD_ISEDITABLE "y"
-#define CD_ISNOTEDITABLE "n"
+#define CD_ISEDITABLE "y"
+#define CD_ISNOTEDITABLE "n"
+
-#define CD_TYPE (0)
-#define CD_EDITABLE (1)
-#define CD_CONTENT (2)
+extern const char *const must_have_files[];
+
+bool is_editable_file(const char *file_name);
-// currently, vector always has exactly 3 elements -> <type, editable, content>
// <key, data>
typedef map_vector_string_t map_crash_data_t;
-
typedef std::vector<map_crash_data_t> vector_map_crash_data_t;
-void add_to_crash_data(map_crash_data_t& pCrashData,
- const char *pItem,
- const char *pContent);
-
void add_to_crash_data_ext(map_crash_data_t& pCrashData,
const char *pItem,
const char *pType,
const char *pEditable,
const char *pContent);
+// Uses type:CD_TXT, editable:CD_ISNOTEDITABLE
+void add_to_crash_data(map_crash_data_t& pCrashData,
+ const char *pItem,
+ const char *pContent);
+
+const char *get_crash_data_item_content_or_NULL(const map_crash_data_t& crash_data, const char *key);
+// Aborts if key is not found:
+const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key);
-const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data,
- const char *key);
+void log_map_crash_data(const map_crash_data_t& data, const char *name);
#endif
diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp
index 5dc4298a..2fc2109a 100644
--- a/lib/Plugins/Bugzilla.cpp
+++ b/lib/Plugins/Bugzilla.cpp
@@ -297,7 +297,7 @@ uint32_t ctx::new_bug(const map_crash_data_t& pCrashData)
const std::string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT);
const std::string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE);
const std::string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE);
- const std::string& uuid = get_crash_data_item_content(pCrashData, CD_UUID);
+ const std::string& uuid = get_crash_data_item_content(pCrashData, CD_DUPHASH);
std::string summary = "[abrt] crash in " + package;
std::string status_whiteboard = "abrt_hash:" + uuid;
@@ -444,7 +444,7 @@ std::string CReporterBugzilla::Report(const map_crash_data_t& pCrashData,
}
const std::string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT);
- const std::string& uuid = get_crash_data_item_content(pCrashData, CD_UUID);
+ const std::string& uuid = get_crash_data_item_content(pCrashData, CD_DUPHASH);
try
{
ctx bz_server(BugzillaXMLRPC.c_str(), NoSSLVerify);
diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp
index 1bc51f97..3580a3b4 100644
--- a/lib/Plugins/Catcut.cpp
+++ b/lib/Plugins/Catcut.cpp
@@ -272,7 +272,7 @@ ctx::new_bug(const char *auth_cookie, const map_crash_data_t& pCrashData)
const string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT);
const string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE);
const string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE);
- const string& uuid = get_crash_data_item_content(pCrashData, CD_UUID);
+ const string& uuid = get_crash_data_item_content(pCrashData, CD_DUPHASH);
string summary = "[abrt] crash in " + package;
string status_whiteboard = "abrt_hash:" + uuid;
diff --git a/lib/Plugins/FileTransfer.cpp b/lib/Plugins/FileTransfer.cpp
index b08ecd51..e28fbbee 100644
--- a/lib/Plugins/FileTransfer.cpp
+++ b/lib/Plugins/FileTransfer.cpp
@@ -25,12 +25,6 @@
#include <iostream>
#include <sstream>
#include <fstream>
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <zip.h>
#include <libtar.h>
#include <bzlib.h>
diff --git a/lib/Plugins/Mailx.cpp b/lib/Plugins/Mailx.cpp
index ae8c2dc9..2ee96455 100644
--- a/lib/Plugins/Mailx.cpp
+++ b/lib/Plugins/Mailx.cpp
@@ -74,13 +74,13 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData,
args = append_str_to_vector(args, arg_size, MAILX_COMMAND);
//TODO: move email body generation to make_descr.cpp
- std::string binaryFiles, commonFiles, additionalFiles, UUIDFile;
+ std::string binaryFiles, commonFiles, additionalFiles, DUPHASHFile;
map_crash_data_t::const_iterator it;
for (it = pCrashData.begin(); it != pCrashData.end(); it++)
{
if (it->second[CD_TYPE] == CD_TXT)
{
- if (it->first != CD_UUID
+ if (it->first != CD_DUPHASH
&& it->first != FILENAME_ARCHITECTURE
&& it->first != FILENAME_KERNEL
&& it->first != FILENAME_PACKAGE
@@ -90,12 +90,12 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData,
additionalFiles += it->second[CD_CONTENT];
additionalFiles += "\n\n";
}
- else if (it->first == CD_UUID)
+ else if (it->first == CD_DUPHASH)
{
- UUIDFile += it->first;
- UUIDFile += "\n-----\n";
- UUIDFile += it->second[CD_CONTENT];
- UUIDFile += "\n\n";
+ DUPHASHFile += it->first;
+ DUPHASHFile += "\n-----\n";
+ DUPHASHFile += it->second[CD_CONTENT];
+ DUPHASHFile += "\n\n";
}
else
{
@@ -117,9 +117,9 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData,
}
}
- std::string emailBody = "Duplicity check\n";
+ std::string emailBody = "Duplicate check\n";
emailBody += "=====\n\n";
- emailBody += UUIDFile;
+ emailBody += DUPHASHFile;
emailBody += "\nCommon information\n";
emailBody += "=====\n\n";
emailBody += commonFiles;
@@ -135,7 +135,7 @@ std::string CMailx::Report(const map_crash_data_t& pCrashData,
args = append_str_to_vector(args, arg_size, m_sEmailTo.c_str());
update_client(_("Sending an email..."));
- const char *uid_str = get_crash_data_item_content(pCrashData, CD_MWUID).c_str();
+ const char *uid_str = get_crash_data_item_content(pCrashData, FILENAME_UID).c_str();
exec_and_feed_input(xatoi_u(uid_str), emailBody.c_str(), args);
while (*args)
diff --git a/lib/Plugins/TicketUploader.h b/lib/Plugins/TicketUploader.h
index fcc59f06..7a371a3a 100644
--- a/lib/Plugins/TicketUploader.h
+++ b/lib/Plugins/TicketUploader.h
@@ -27,7 +27,6 @@
#include "Plugin.h"
#include "Reporter.h"
-//#include "CrashTypes.h"
class CTicketUploader : public CReporter
{
diff --git a/lib/Utils/CrashTypes.cpp b/lib/Utils/CrashTypes.cpp
index 4824e507..4fc93337 100644
--- a/lib/Utils/CrashTypes.cpp
+++ b/lib/Utils/CrashTypes.cpp
@@ -20,6 +20,40 @@
#include "abrtlib.h"
#include "CrashTypes.h"
+const char *const must_have_files[] = {
+ FILENAME_ARCHITECTURE,
+ FILENAME_KERNEL ,
+ FILENAME_PACKAGE ,
+ FILENAME_COMPONENT ,
+ FILENAME_RELEASE ,
+ FILENAME_EXECUTABLE ,
+ NULL
+};
+
+static const char *const editable_files[] = {
+ FILENAME_DESCRIPTION,
+ FILENAME_COMMENT ,
+ FILENAME_REPRODUCE ,
+ FILENAME_BACKTRACE ,
+ NULL
+};
+
+static bool is_editable(const char *name, const char *const *v)
+{
+ while (*v) {
+ if (strcmp(*v, name) == 0)
+ return true;
+ v++;
+ }
+ return false;
+}
+
+bool is_editable_file(const char *file_name)
+{
+ return is_editable(file_name, editable_files);
+}
+
+
void add_to_crash_data_ext(map_crash_data_t& pCrashData,
const char *pItem,
const char *pType,
@@ -28,9 +62,10 @@ void add_to_crash_data_ext(map_crash_data_t& pCrashData,
{
map_crash_data_t::iterator it = pCrashData.find(pItem);
if (it == pCrashData.end()) {
- pCrashData[pItem].push_back(pType);
- pCrashData[pItem].push_back(pEditable);
- pCrashData[pItem].push_back(pContent);
+ vector_string_t& v = pCrashData[pItem]; /* create empty vector */
+ v.push_back(pType);
+ v.push_back(pEditable);
+ v.push_back(pContent);
return;
}
vector_string_t& v = it->second;
@@ -48,14 +83,50 @@ void add_to_crash_data(map_crash_data_t& pCrashData,
add_to_crash_data_ext(pCrashData, pItem, CD_TXT, CD_ISNOTEDITABLE, pContent);
}
-const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key)
+static const std::string* helper_get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key)
{
map_crash_data_t::const_iterator it = crash_data.find(key);
if (it == crash_data.end()) {
- error_msg_and_die("Error accessing crash data: no ['%s']", key);
+ return NULL;
}
if (it->second.size() <= CD_CONTENT) {
+ return NULL;
+ }
+ return &it->second[CD_CONTENT];
+}
+
+const std::string& get_crash_data_item_content(const map_crash_data_t& crash_data, const char *key)
+{
+ const std::string* sp = helper_get_crash_data_item_content(crash_data, key);
+ if (sp == NULL) {
+ if (crash_data.find(key) == crash_data.end())
+ error_msg_and_die("Error accessing crash data: no ['%s']", key);
error_msg_and_die("Error accessing crash data: no ['%s'][%d]", key, CD_CONTENT);
}
- return it->second[CD_CONTENT];
+ return *sp;
+}
+
+const char *get_crash_data_item_content_or_NULL(const map_crash_data_t& crash_data, const char *key)
+{
+ const std::string* sp = helper_get_crash_data_item_content(crash_data, key);
+ if (!sp) {
+ return NULL;
+ }
+ return sp->c_str();
+}
+
+void log_map_crash_data(const map_crash_data_t& data, const char *name)
+{
+ map_crash_data_t::const_iterator it = data.begin();
+ while (it != data.end())
+ {
+ ssize_t sz = it->second.size();
+ log("%s[%s]:%s/%s/'%.20s'",
+ name, it->first.c_str(),
+ sz > 0 ? it->second[0].c_str() : "<NO [0]>",
+ sz > 1 ? it->second[1].c_str() : "<NO [1]>",
+ sz > 2 ? it->second[2].c_str() : "<NO [2]>"
+ );
+ it++;
+ }
}
diff --git a/lib/Utils/make_descr.cpp b/lib/Utils/make_descr.cpp
index e74e9b1d..a3ff5e24 100644
--- a/lib/Utils/make_descr.cpp
+++ b/lib/Utils/make_descr.cpp
@@ -58,13 +58,13 @@ string make_description_bz(const map_crash_data_t& pCrashData)
map_crash_data_t::const_iterator end = pCrashData.end();
bool was_multiline = 0;
- it = pCrashData.find(CD_REPRODUCE);
+ it = pCrashData.find(FILENAME_REPRODUCE);
if (it != end && it->second[CD_CONTENT] != "1.\n2.\n3.\n")
{
add_content(was_multiline, description, "How to reproduce", it->second[CD_CONTENT].c_str());
}
- it = pCrashData.find(CD_COMMENT);
+ it = pCrashData.find(FILENAME_COMMENT);
if (it != end)
{
add_content(was_multiline, description, "Comment", it->second[CD_CONTENT].c_str());
@@ -80,11 +80,11 @@ string make_description_bz(const map_crash_data_t& pCrashData)
{
if (content.size() <= CD_TEXT_ATT_SIZE)
{
- if (filename != CD_UUID
+ if (filename != CD_DUPHASH
&& filename != FILENAME_ARCHITECTURE
&& filename != FILENAME_RELEASE
- && filename != CD_REPRODUCE
- && filename != CD_COMMENT
+ && filename != FILENAME_REPRODUCE
+ && filename != FILENAME_COMMENT
) {
add_content(was_multiline, description, filename.c_str(), content.c_str());
}
@@ -147,7 +147,7 @@ string make_description_catcut(const map_crash_data_t& pCrashData)
map_crash_data_t::const_iterator it;
string howToReproduce;
- it = pCrashData.find(CD_REPRODUCE);
+ it = pCrashData.find(FILENAME_REPRODUCE);
if (it != end)
{
howToReproduce = "\n\nHow to reproduce\n"
@@ -155,7 +155,7 @@ string make_description_catcut(const map_crash_data_t& pCrashData)
howToReproduce += it->second[CD_CONTENT];
}
string comment;
- it = pCrashData.find(CD_COMMENT);
+ it = pCrashData.find(FILENAME_COMMENT);
if (it != end)
{
comment = "\n\nComment\n"
@@ -178,11 +178,11 @@ string make_description_catcut(const map_crash_data_t& pCrashData)
{
if (content.length() <= CD_TEXT_ATT_SIZE)
{
- if (filename != CD_UUID
+ if (filename != CD_DUPHASH
&& filename != FILENAME_ARCHITECTURE
&& filename != FILENAME_RELEASE
- && filename != CD_REPRODUCE
- && filename != CD_COMMENT
+ && filename != FILENAME_REPRODUCE
+ && filename != FILENAME_COMMENT
) {
pDescription += '\n';
pDescription += filename;
diff --git a/lib/Utils/test.cpp b/lib/Utils/test.cpp
index 160c107b..3711ef18 100644
--- a/lib/Utils/test.cpp
+++ b/lib/Utils/test.cpp
@@ -84,16 +84,16 @@ int main(int argc, char** argv)
if (middleWare.SaveDebugDump(argv[1], crashInfo))
{
std::cout << "Application Crashed! " <<
- crashInfo[CD_PACKAGE][CD_CONTENT] << ", " <<
- crashInfo[CD_EXECUTABLE][CD_CONTENT] << ", " <<
+ crashInfo[FILENAME_PACKAGE][CD_CONTENT] << ", " <<
+ crashInfo[FILENAME_EXECUTABLE][CD_CONTENT] << ", " <<
crashInfo[CD_COUNT][CD_CONTENT] << ", " << std::endl;
/* Get Report, so user can change data (remove private stuff)
* If we do not want user interaction, just send data immediately
*/
map_crash_data_t crashReport;
- middleWare.CreateCrashReport(crashInfo[CD_UUID][CD_CONTENT],
- crashInfo[CD_UID][CD_CONTENT],
+ middleWare.CreateCrashReport(crashInfo[CD_DUPHASH][CD_CONTENT],
+ crashInfo[FILENAME_UID][CD_CONTENT],
crashReport);
/* Report crash */
middleWare.Report(crashReport);
diff --git a/po/nl.po b/po/nl.po
index c66b3bda..d47aaca7 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -7,13 +7,12 @@
# Geert Warrink <geert.warrink@onsnet.nu>, 2009.
# Richard van der Luit <nippur@fedoraproject.org>, 2009.
# Geert Warrink <geert.warrink@onsnet.nu>, 2009, 2010.
-#: ../src/Gui/CCReporterDialog.py:208
msgid ""
msgstr ""
"Project-Id-Version: abrt.master\n"
"Report-Msgid-Bugs-To: jmoskovc@redhat.com\n"
-"POT-Creation-Date: 2010-01-14 15:35+0000\n"
-"PO-Revision-Date: 2010-01-14 17:50+0100\n"
+"POT-Creation-Date: 2010-01-21 04:02+0000\n"
+"PO-Revision-Date: 2010-01-21 15:21+0100\n"
"Last-Translator: Geert Warrink <geert.warrink@onsnet.nu>\n"
"Language-Team: nl <fedora-trans-list@redhat.com>\n"
"MIME-Version: 1.0\n"
@@ -51,10 +50,6 @@ msgstr "Rapporteer plugins"
msgid "Database plugins"
msgstr "Databse plugins"
-#: ../src/Gui/ABRTPlugin.py:99
-msgid "Plugin name is not set, can't load its settings"
-msgstr "Plugin naam is niet ingesteld, kan zijn instellingen niet laden"
-
#: ../src/Gui/CCDBusBackend.py:74 ../src/Gui/CCDBusBackend.py:97
msgid "Can't connect to system dbus"
msgstr "Kan niet verbinden met systeem dbus"
@@ -79,7 +74,8 @@ msgstr "(C) 2009 Red Hat, Inc."
msgid "About ABRT"
msgstr "Over ABRT"
-#: ../src/Gui/ccgui.glade.h:3 ../src/Gui/abrt.desktop.in.h:1
+#: ../src/Gui/ccgui.glade.h:3 ../src/Gui/CCMainWindow.py:9
+#: ../src/Gui/report.glade.h:15 ../src/Gui/abrt.desktop.in.h:1
msgid "Automatic Bug Reporting Tool"
msgstr "Automatisch bug rapporteer gereedschap"
@@ -103,7 +99,7 @@ msgstr "Wacht a.u.b..."
msgid "Plugins"
msgstr "Plugins"
-#: ../src/Gui/ccgui.glade.h:9 ../src/Gui/report.glade.h:6
+#: ../src/Gui/ccgui.glade.h:9
msgid "Report"
msgstr "Rapport"
@@ -148,31 +144,31 @@ msgid "_Help"
msgstr "_Hulp"
#. add pixbuff separatelly
-#: ../src/Gui/CCMainWindow.py:76
+#: ../src/Gui/CCMainWindow.py:78
msgid "Icon"
msgstr "Icoon"
-#: ../src/Gui/CCMainWindow.py:84
+#: ../src/Gui/CCMainWindow.py:86
msgid "Package"
msgstr "Pakket"
-#: ../src/Gui/CCMainWindow.py:85
+#: ../src/Gui/CCMainWindow.py:87
msgid "Application"
msgstr "Toepassing"
-#: ../src/Gui/CCMainWindow.py:86
+#: ../src/Gui/CCMainWindow.py:88
msgid "Date"
msgstr "Datum"
-#: ../src/Gui/CCMainWindow.py:87
+#: ../src/Gui/CCMainWindow.py:89
msgid "Crash count"
msgstr "Crash count"
-#: ../src/Gui/CCMainWindow.py:88
+#: ../src/Gui/CCMainWindow.py:90
msgid "User"
msgstr "Gebruiker"
-#: ../src/Gui/CCMainWindow.py:156
+#: ../src/Gui/CCMainWindow.py:158
#, python-format
msgid ""
"Can't show the settings dialog\n"
@@ -181,7 +177,7 @@ msgstr ""
"Kan de instellingen dialoog niet tonen\n"
"%s"
-#: ../src/Gui/CCMainWindow.py:167
+#: ../src/Gui/CCMainWindow.py:169
#, python-format
msgid ""
"Unable to finish current task!\n"
@@ -191,7 +187,7 @@ msgstr ""
"%s"
#. there is something wrong with the daemon if we cant get the dumplist
-#: ../src/Gui/CCMainWindow.py:194
+#: ../src/Gui/CCMainWindow.py:196
#, python-format
msgid ""
"Error while loading the dumplist.\n"
@@ -200,15 +196,19 @@ msgstr ""
"Fout tijdens het laden van de dumplijst.\n"
"%s"
-#: ../src/Gui/CCMainWindow.py:231
+#: ../src/Gui/CCMainWindow.py:233
+msgid "This crash has been reported:\n"
+msgstr "Deze crash is gerapporteerd:\n"
+
+#: ../src/Gui/CCMainWindow.py:234
msgid "<b>This crash has been reported:</b>\n"
msgstr "<b>Deze crash is gerapporteerd:</b>\n"
-#: ../src/Gui/CCMainWindow.py:241
+#: ../src/Gui/CCMainWindow.py:250
msgid "<b>Not reported!</b>"
msgstr "<b>Niet gerapporteerd!</b>"
-#: ../src/Gui/CCMainWindow.py:290
+#: ../src/Gui/CCMainWindow.py:298
msgid ""
"Unable to get report!\n"
"Debuginfo is missing?"
@@ -216,7 +216,7 @@ msgstr ""
"Kan geen rapport krijgen!\n"
"Mist debuginfo?"
-#: ../src/Gui/CCMainWindow.py:309
+#: ../src/Gui/CCMainWindow.py:318
#, python-format
msgid ""
"Reporting failed!\n"
@@ -225,25 +225,16 @@ msgstr ""
"Rapporteren mislukte!\n"
"%s"
-#: ../src/Gui/CCMainWindow.py:328 ../src/Gui/CCMainWindow.py:355
+#: ../src/Gui/CCMainWindow.py:337 ../src/Gui/CCMainWindow.py:364
#, python-format
msgid "Error getting the report: %s"
msgstr "Fout tijdens het verkrijgen van het rapport: %s"
-#: ../src/Gui/CCReporterDialog.py:136
-#, python-format
-msgid ""
-"Can't save plugin settings:\n"
-" %s"
-msgstr ""
-"Kan de plugin instellingen niet opslaan:\n"
-" %s"
-
-#: ../src/Gui/CCReporterDialog.py:194
-msgid "Brief description how to reproduce this or what you did..."
-msgstr "Korte beschrijving hoe dit te reproduceren is of wat je deed..."
+#: ../src/Gui/CCReporterDialog.py:90
+msgid "You must agree with submitting the backtrace."
+msgstr "Je moet het goed vinden om de backtrace op te sturen."
-#: ../src/Gui/CCReporterDialog.py:239
+#: ../src/Gui/CCReporterDialog.py:101
#, python-format
msgid ""
"Reporting disabled because the backtrace is unusable.\n"
@@ -256,11 +247,11 @@ msgstr ""
"<b>debuginfo-install %s</b> \n"
"en gebruik dan de Verversen knop om de backtrace opnieuw te genereren."
-#: ../src/Gui/CCReporterDialog.py:241
+#: ../src/Gui/CCReporterDialog.py:103
msgid "The backtrace is unusable, you can't report this!"
msgstr "De backtrace in niet bruikbaar, je kunt dit niet rapporteren!"
-#: ../src/Gui/CCReporterDialog.py:246
+#: ../src/Gui/CCReporterDialog.py:106
msgid ""
"The backtrace is incomplete, please make sure you provide good steps to "
"reproduce."
@@ -268,18 +259,20 @@ msgstr ""
"De backtrace is niet compleet, wees er zeker van om voor het genereren de "
"juiste stappen op te volgen."
-#: ../src/Gui/CCReporterDialog.py:296
+#: ../src/Gui/CCReporterDialog.py:148
#, python-format
msgid ""
-"<b>WARNING</b>, you're about to send data which might contain sensitive "
-"information.\n"
-"Do you really want to send <b>%s</b>?\n"
+"Can't save plugin settings:\n"
+" %s"
msgstr ""
-"<b>WAARSCHUWING</b>, je staat op het punt om data te versturen die gevoelige "
-"informatie kan bevatten\n"
-"Wil je <b>%s</b> echt versturen?\n"
+"Kan de plugin instellingen niet opslaan:\n"
+" %s"
+
+#: ../src/Gui/CCReporterDialog.py:266
+msgid "Brief description how to reproduce this or what you did..."
+msgstr "Korte beschrijving hoe dit te reproduceren is of wat je deed..."
-#: ../src/Gui/dialogs.glade.h:1 ../src/Gui/report.glade.h:5
+#: ../src/Gui/dialogs.glade.h:1 ../src/Gui/report.glade.h:17
msgid "Log"
msgstr "Log"
@@ -310,18 +303,68 @@ msgid " "
msgstr " "
#: ../src/Gui/report.glade.h:2
-msgid "<b>Comment</b>"
-msgstr "<b>Commentaar</b>"
+msgid "<b>Attachments</b>"
+msgstr "<b>Bijlagen</b>"
#: ../src/Gui/report.glade.h:3
-msgid "<b>Following items will be sent</b>"
-msgstr "<b>De volgende items zullen verzonden worden</b>"
+msgid "<b>Backtrace</b>"
+msgstr "<b>Backtrace</b>"
#: ../src/Gui/report.glade.h:4
+msgid "<b>Comment</b>"
+msgstr "<b>Commentaar</b>"
+
+#: ../src/Gui/report.glade.h:5
msgid "<b>How to reproduce (in a few simple steps)</b>"
msgstr "<b>Hoe het te reproduceren (in een paar eenvoudige stappen)</b>"
+#: ../src/Gui/report.glade.h:6
+msgid "<b>Please fix the following problems</b>"
+msgstr "<b>Los a.u.b. de volgende problemen op</b>"
+
#: ../src/Gui/report.glade.h:7
+msgid "<span fgcolor=\"blue\">Architecture:</span>"
+msgstr "<span fgcolor=\"blue\">Architectuur:</span>"
+
+#: ../src/Gui/report.glade.h:8
+msgid "<span fgcolor=\"blue\">Cmdline:</span>"
+msgstr "<span fgcolor=\"blue\">Cmdregel:</span>"
+
+#: ../src/Gui/report.glade.h:9
+msgid "<span fgcolor=\"blue\">Component:</span>"
+msgstr "<span fgcolor=\"blue\">Onderdeel:</span>"
+
+#: ../src/Gui/report.glade.h:10
+msgid "<span fgcolor=\"blue\">Executable:</span>"
+msgstr "<span fgcolor=\"blue\">Uitvoerbaar programma:</span>"
+
+#: ../src/Gui/report.glade.h:11
+msgid "<span fgcolor=\"blue\">Kernel:</span>"
+msgstr "<span fgcolor=\"blue\">Kernel:</span>"
+
+#: ../src/Gui/report.glade.h:12
+msgid "<span fgcolor=\"blue\">Package:</span>"
+msgstr "<span fgcolor=\"blue\">Pakket:</span>"
+
+#: ../src/Gui/report.glade.h:13
+msgid "<span fgcolor=\"blue\">Reason:</span>"
+msgstr "<span fgcolor=\"blue\">Reden:</span>"
+
+#: ../src/Gui/report.glade.h:14
+msgid "<span fgcolor=\"blue\">Release:</span>"
+msgstr "<span fgcolor=\"blue\">Vrijgave:</span>"
+
+#: ../src/Gui/report.glade.h:16
+msgid "I agree to submit this backtrace, which could contain sensitive data"
+msgstr ""
+"Ik ben er mee eens om deze backtrace in te dienen, hoewel hij gevoelige data "
+"kan bevatten"
+
+#: ../src/Gui/report.glade.h:18
+msgid "N/A"
+msgstr "n.v.t."
+
+#: ../src/Gui/report.glade.h:19
msgid "Send"
msgstr "Verzenden"
@@ -441,12 +484,12 @@ msgstr "gtk-ok"
msgid "View and report application crashes"
msgstr "Bekijk en rapporteer crashes van toepassingen"
-#: ../src/Applet/Applet.cpp:79
+#: ../src/Applet/Applet.cpp:78
#, c-format
msgid "A crash in package %s has been detected"
msgstr "Een crash in pakket %s is ontdekt"
-#: ../src/Applet/Applet.cpp:254
+#: ../src/Applet/Applet.cpp:253
msgid "ABRT service is not running"
msgstr "ABRT service draait niet"
@@ -454,7 +497,7 @@ msgstr "ABRT service draait niet"
msgid "Warning"
msgstr "Waarschuwing"
-#: ../src/Daemon/Daemon.cpp:474
+#: ../src/Daemon/Daemon.cpp:473
msgid ""
"Report size exceeded the quota. Please check system's MaxCrashReportsSize "
"value in abrt.conf."
@@ -476,51 +519,51 @@ msgstr "Nieuwe bug id: %i"
msgid "Checking for duplicates..."
msgstr "Controleren voor dubbele..."
-#: ../lib/Plugins/Bugzilla.cpp:445
-msgid "Logging into bugzilla..."
-msgstr "Inloggen bij bugzilla..."
-
-#: ../lib/Plugins/Bugzilla.cpp:449
+#: ../lib/Plugins/Bugzilla.cpp:448
msgid "Empty login and password. Please check Bugzilla.conf"
msgstr "Leeg login en wachtwoord. Check a.u.b. Bugzilla.conf"
+#: ../lib/Plugins/Bugzilla.cpp:450
+msgid "Logging into bugzilla..."
+msgstr "Inloggen bij bugzilla..."
+
#: ../lib/Plugins/Bugzilla.cpp:455
msgid "Checking CC..."
msgstr "Controleren van CC..."
-#: ../lib/Plugins/Bugzilla.cpp:464
+#: ../lib/Plugins/Bugzilla.cpp:466
msgid "Creating new bug..."
msgstr "Nieuwe bug aanmaken..."
-#: ../lib/Plugins/Bugzilla.cpp:468
+#: ../lib/Plugins/Bugzilla.cpp:470
msgid "Logging out..."
msgstr "Uitloggen..."
-#: ../lib/Plugins/Kerneloops.cpp:37
+#: ../lib/Plugins/Kerneloops.cpp:35
msgid "Getting local universal unique identification"
msgstr "Verkrijgen van locale universele unieke identificatie"
-#: ../lib/Plugins/CCpp.cpp:257
+#: ../lib/Plugins/CCpp.cpp:253
msgid "Generating backtrace"
msgstr "Aangemaakte backtrace"
-#: ../lib/Plugins/CCpp.cpp:376
+#: ../lib/Plugins/CCpp.cpp:375
msgid "Starting debuginfo installation"
msgstr "Start debuginfo installatie"
-#: ../lib/Plugins/CCpp.cpp:527
+#: ../lib/Plugins/CCpp.cpp:526
msgid "Getting local universal unique identification..."
msgstr "Verkrijgen van locale universele unieke identificatie..."
-#: ../lib/Plugins/CCpp.cpp:546
+#: ../lib/Plugins/CCpp.cpp:545
msgid "Getting global universal unique identification..."
msgstr "Verkrijgen van golbale universele unieke identificatie..."
-#: ../lib/Plugins/CCpp.cpp:725
+#: ../lib/Plugins/CCpp.cpp:723
msgid "Skipping debuginfo installation"
msgstr "Sla debuginfo installatie over"
-#: ../lib/Plugins/KerneloopsReporter.cpp:102
+#: ../lib/Plugins/KerneloopsReporter.cpp:100
msgid "Creating and submitting a report..."
msgstr "Aanmaken en indienen van rapport..."
@@ -552,11 +595,11 @@ msgstr "Kan geen archief maken en versturen: %s"
msgid "Can't create and send an archive %s"
msgstr "Kan archief %s niet aanmaken en versturen"
-#: ../lib/Plugins/KerneloopsScanner.cpp:84
+#: ../lib/Plugins/KerneloopsScanner.cpp:79
msgid "Creating kernel oops crash reports..."
msgstr "Aanmaken van kernel oops crash rapporten..."
-#: ../lib/Plugins/Mailx.cpp:147
+#: ../lib/Plugins/Mailx.cpp:137
msgid "Sending an email..."
msgstr "Versturen van email..."
@@ -573,6 +616,21 @@ msgstr "sosreport draaien: %s"
msgid "done running sosreport"
msgstr "klaar met het draaien van sosreport"
+#~ msgid "Plugin name is not set, can't load its settings"
+#~ msgstr "Plugin naam is niet ingesteld, kan zijn instellingen niet laden"
+
+#~ msgid ""
+#~ "<b>WARNING</b>, you're about to send data which might contain sensitive "
+#~ "information.\n"
+#~ "Do you really want to send <b>%s</b>?\n"
+#~ msgstr ""
+#~ "<b>WAARSCHUWING</b>, je staat op het punt om data te versturen die "
+#~ "gevoelige informatie kan bevatten\n"
+#~ "Wil je <b>%s</b> echt versturen?\n"
+
+#~ msgid "<b>Following items will be sent</b>"
+#~ msgstr "<b>De volgende items zullen verzonden worden</b>"
+
#~ msgid "Searching for debug-info packages..."
#~ msgstr "Zoeken naar debug-info pakketten..."
@@ -585,9 +643,6 @@ msgstr "klaar met het draaien van sosreport"
#~ msgid "Starting report creation..."
#~ msgstr "Beginnen met rapport aanmaken..."
-#~ msgid "<span color=\"white\">Description</span>"
-#~ msgstr "<span color=\"white\">Beschrijving</span>"
-
#~ msgid "Working..."
#~ msgstr "Ben bezig..."
diff --git a/scripts/abrt-bz-stats b/scripts/abrt-bz-stats
index 3fb02bca..fd222dc9 100755
--- a/scripts/abrt-bz-stats
+++ b/scripts/abrt-bz-stats
@@ -13,6 +13,9 @@ import subprocess
import datetime
import pickle
+#
+# Parse the command line input
+#
parser = OptionParser(version="%prog 1.0")
parser.add_option("-u", "--user", dest="user",
help="Bugzilla user name (REQUIRED)", metavar="USERNAME")
@@ -21,7 +24,6 @@ parser.add_option("-p", "--password", dest="password",
parser.add_option("-b", "--bugzilla", dest="bugzilla",
help="Bugzilla URL (defaults to Red Hat Bugzilla)", metavar="URL")
(options, args) = parser.parse_args()
-
if not options.user or len(options.user) == 0:
parser.error("User name is required.\nTry {0} --help".format(sys.argv[0]))
if not options.password or len(options.password) == 0:
@@ -29,6 +31,9 @@ if not options.password or len(options.password) == 0:
if not options.bugzilla or len(options.bugzilla) == 0:
options.bugzilla = "https://bugzilla.redhat.com/xmlrpc.cgi"
+#
+# Connect to Bugzilla and get the list of all bugs reported by ABRT
+#
bz = RHBugzilla()
bz.connect(options.bugzilla)
bz.login(options.user, options.password)
@@ -37,47 +42,150 @@ buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboar
total = len(buginfos)
print "{0} bugs found.".format(total)
+#
+# Load cache from previous run. Speeds up the case Bugzilla closes connection.
+#
buginfos_loaded = {}
if os.path.isfile("cache"):
f = open("cache", 'r')
buginfos_loaded = pickle.load(f)
f.close()
+def save_to_cache():
+ global buginfos_loaded
+ f = open("cache", 'w')
+ pickle.dump(buginfos_loaded, f, 2)
+ f.close()
+
+#
+# Load data from Bugzilla
+#
count = 0
for buginfo in buginfos:
count += 1
print "{0}/{1}".format(count, total)
- dtkey = buginfo.delta_ts[0:7] # YEAR-MONTH
- statuskey = buginfo.bug_status
- if buginfo.resolution != "":
- statuskey += "_" + buginfo.resolution
- if not buginfos_loaded.has_key(buginfo.bug_id):
- buginfos_loaded[buginfo.bug_id] = (dtkey, statuskey)
+
if count % 100 == 0:
- f = open("cache", 'w')
- pickle.dump(buginfos_loaded, f, 2)
- f.close()
+ save_to_cache()
+
+ if buginfos_loaded.has_key(buginfo.bug_id):
+ continue
+
+ # creation date, format YEAR-MONTH
+ created = buginfo.creation_ts[0:7].replace(".", "-")
+ # last change to bug, format YEAR-MONTH
+ lastchange = buginfo.delta_ts[0:7].replace(".", "-")
+ status = buginfo.bug_status # status during the last change
+ if buginfo.resolution != "":
+ status += "_" + buginfo.resolution
+ buginfos_loaded[buginfo.bug_id] = {
+ 'created':created,
+ 'lastchange':lastchange,
+ 'status':status,
+ 'component':buginfo.component}
+
bz.logout()
+save_to_cache()
-stats = {}
-for buginfo in buginfos_loaded.values():
- if buginfo[0] in stats:
- stat = stats[buginfo[0]]
- if buginfo[1] in stat:
- stat[buginfo[1]] += 1
+#
+# Interpret data from Bugzilla
+#
+# Bugs reported this month by ABRT
+# Bugs closed as useful this month by ABRT
+# Bugs closed as waste this month by ABRT
+# Top crashers this month.
+#
+class Month:
+ def __init__(self):
+ # Number of bugs reported to certain component this month.
+ self.components = {}
+
+ self.closed_as_useful = 0
+ self.closed_as_waste = 0
+ self.closed_as_other = 0
+
+ def bugs_reported(self):
+ result = 0
+ for component in self.components.values():
+ result += component
+ return result
+
+ def top_crashers(self):
+ """
+ Top five components causing crash this month.
+ Returns list of tuples (component, number of crashes)
+ """
+ result = sorted(self.components.items(), key=lambda x: x[1])
+ result.reverse()
+ return result[0:5]
+
+ def closed_as_useful_percentage(self):
+ return int(100 * self.closed_as_useful / self.closed())
+
+ def closed_as_waste_percentage(self):
+ return int(100 * self.closed_as_waste / self.closed())
+
+ def closed_as_other_percentage(self):
+ return int(100 * self.closed_as_other / self.closed())
+
+ def closed(self):
+ return self.closed_as_useful + self.closed_as_waste + self.closed_as_other
+
+ def add_component_crash(self, component):
+ if component in self.components:
+ self.components[component] += 1
else:
- stat[buginfo[1]] = 1
+ self.components[component] = 1
+
+ def add_resolution(self, resolution):
+ if resolution in ["CLOSED_NOTABUG", "CLOSED_WONTFIX", "CLOSED_DEFERRED", "CLOSED_WORKSFORME"]:
+ self.closed_as_other += 1
+ elif resolution in ["CLOSED_CURRENTRELEASE", "CLOSED_RAWHIDE", "CLOSED_ERRATA", \
+ "CLOSED_UPSTREAM", "CLOSED_NEXTRELEASE"]:
+ self.closed_as_useful += 1
+ elif resolution in ["CLOSED_DUPLICATE", "CLOSED_CANTFIX", "CLOSED_INSUFFICIENT_DATA"]:
+ self.closed_as_waste += 1
+
+
+stats = {} # key == YEAR-MONTH, value == Month()
+
+def get_month(month):
+ global stats
+ if month in stats:
+ return stats[month]
else:
- stats[buginfo[0]] = { buginfo[1]:1 }
+ stats[month] = Month()
+ return stats[month]
+for buginfo in buginfos_loaded.values():
+ # Bugs reported this month by ABRT
+ # Top crashers this month
+ month = get_month(buginfo['created'])
+ month.add_component_crash(buginfo['component'])
+
+ # Bugs closed as useful this month by ABRT
+ # Bugs closed as waste this month by ABRT
+ month = get_month(buginfo['lastchange'])
+ month.add_resolution(buginfo['status'])
+
+#
+# Print interpreted data
+#
print "STATS"
print "=========================================================================="
months = stats.keys()
months.sort()
for month in months:
- stat = stats[month]
- statuses = stat.keys()
- statuses.sort()
- print "Month ", month
- for status in statuses:
- print status, stat[status]
+ m = stats[month]
+ print "MONTH ", month
+ print " -", m.bugs_reported(), "bugs reported"
+ if m.closed_as_useful > 0:
+ print " -", m.closed_as_useful, "bugs (" + str(m.closed_as_useful_percentage()) + "%) closed (ABRT was useful)"
+ if m.closed_as_waste > 0:
+ print " -", m.closed_as_waste, "bugs (" + str(m.closed_as_waste_percentage())+ "%) closed (ABRT was not useful)"
+ if m.closed_as_other > 0:
+ print " -", m.closed_as_other, "bugs (" + str(m.closed_as_other_percentage()) + "%) closed other way"
+ if len(m.top_crashers()) > 0:
+ print " - top crashers:"
+ for (component, num_crashes) in m.top_crashers():
+ print " # ", component + ":", num_crashes, "crashes"
diff --git a/src/CLI/CLI.cpp b/src/CLI/CLI.cpp
index 2f3b4048..a8786e99 100644
--- a/src/CLI/CLI.cpp
+++ b/src/CLI/CLI.cpp
@@ -53,9 +53,9 @@ static void print_crash_infos(vector_map_crash_data_t& pCrashInfos, int pMode)
for (ii = 0; ii < pCrashInfos.size(); ii++)
{
map_crash_data_t& info = pCrashInfos[ii];
- if (pMode == OPT_GET_LIST_FULL || info[CD_REPORTED][CD_CONTENT] != "1")
+ if (pMode == OPT_GET_LIST_FULL || get_crash_data_item_content(info, CD_REPORTED) != "1")
{
- const char *timestr = info[CD_TIME][CD_CONTENT].c_str();
+ const char *timestr = get_crash_data_item_content(info, FILENAME_TIME).c_str();
long time = strtol(timestr, NULL, 10);
if (time == 0)
error_msg_and_die("Error while converting time string.");
@@ -72,13 +72,13 @@ static void print_crash_infos(vector_map_crash_data_t& pCrashInfos, int pMode)
"\tExecutable : %s\n"
"\tCrash Time : %s\n"
"\tCrash Count: %s\n"),
- ii,
- info[CD_UID][CD_CONTENT].c_str(),
- info[CD_UUID][CD_CONTENT].c_str(),
- info[CD_PACKAGE][CD_CONTENT].c_str(),
- info[CD_EXECUTABLE][CD_CONTENT].c_str(),
- timeloc,
- info[CD_COUNT][CD_CONTENT].c_str()
+ ii,
+ get_crash_data_item_content(info, FILENAME_UID).c_str(),
+ get_crash_data_item_content(info, CD_UUID).c_str(),
+ get_crash_data_item_content(info, FILENAME_PACKAGE).c_str(),
+ get_crash_data_item_content(info, FILENAME_EXECUTABLE).c_str(),
+ timeloc,
+ get_crash_data_item_content(info, CD_COUNT).c_str()
);
}
}
diff --git a/src/CLI/report.cpp b/src/CLI/report.cpp
index 11037ca7..76cd3d5a 100644
--- a/src/CLI/report.cpp
+++ b/src/CLI/report.cpp
@@ -192,13 +192,13 @@ static void write_crash_report(const map_crash_data_t &report, FILE *fp)
fprintf(fp, "# Please check this report. Lines starting with '#' will be ignored.\n"
"# Lines starting with '%%----' separate fields, please do not delete them.\n\n");
- write_crash_report_field(fp, report, CD_COMMENT,
+ write_crash_report_field(fp, report, FILENAME_COMMENT,
_("# Describe the circumstances of this crash below."));
- write_crash_report_field(fp, report, CD_REPRODUCE,
+ write_crash_report_field(fp, report, FILENAME_REPRODUCE,
_("# How to reproduce the crash?"));
write_crash_report_field(fp, report, FILENAME_BACKTRACE,
_("# Stack trace: a list of active stack frames at the time the crash occurred\n# Check that it does not contain any sensitive data such as passwords."));
- write_crash_report_field(fp, report, CD_UUID, _("# UUID"));
+ write_crash_report_field(fp, report, CD_DUPHASH, "# DUPHASH");
write_crash_report_field(fp, report, FILENAME_ARCHITECTURE, _("# Architecture"));
write_crash_report_field(fp, report, FILENAME_CMDLINE, _("# Command line"));
write_crash_report_field(fp, report, FILENAME_COMPONENT, _("# Component"));
@@ -282,10 +282,10 @@ static int read_crash_report_field(const char *text, map_crash_data_t &report,
static int read_crash_report(map_crash_data_t &report, const char *text)
{
int result = 0;
- result |= read_crash_report_field(text, report, CD_COMMENT);
- result |= read_crash_report_field(text, report, CD_REPRODUCE);
+ result |= read_crash_report_field(text, report, FILENAME_COMMENT);
+ result |= read_crash_report_field(text, report, FILENAME_REPRODUCE);
result |= read_crash_report_field(text, report, FILENAME_BACKTRACE);
- result |= read_crash_report_field(text, report, CD_UUID);
+ result |= read_crash_report_field(text, report, CD_DUPHASH);
result |= read_crash_report_field(text, report, FILENAME_ARCHITECTURE);
result |= read_crash_report_field(text, report, FILENAME_CMDLINE);
result |= read_crash_report_field(text, report, FILENAME_COMPONENT);
diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp
index ddfbba49..f1f10e50 100644
--- a/src/Daemon/CommLayerServerDBus.cpp
+++ b/src/Daemon/CommLayerServerDBus.cpp
@@ -190,7 +190,8 @@ static int handle_CreateReport(DBusMessage* call, DBusMessage* reply)
}
long unix_uid = get_remote_uid(call);
- map_crash_data_t report = CreateReport(pUUID, to_string(unix_uid).c_str(), /*force:*/ 0);
+ map_crash_data_t report;
+ CreateReport(pUUID, to_string(unix_uid).c_str(), /*force:*/ 0, report);
DBusMessageIter out_iter;
dbus_message_iter_init_append(reply, &out_iter);
@@ -214,9 +215,9 @@ static int handle_Report(DBusMessage* call, DBusMessage* reply)
return -1;
}
- map_crash_data_t::const_iterator it_comment = argin1.find(CD_COMMENT);
+ map_crash_data_t::const_iterator it_comment = argin1.find(FILENAME_COMMENT);
const char* comment = (it_comment != argin1.end()) ? it_comment->second[CD_CONTENT].c_str() : "";
- map_crash_data_t::const_iterator it_reproduce = argin1.find(CD_REPRODUCE);
+ map_crash_data_t::const_iterator it_reproduce = argin1.find(FILENAME_REPRODUCE);
const char* reproduce = (it_reproduce != argin1.end()) ? it_reproduce->second[CD_CONTENT].c_str() : "";
const char* errmsg = NULL;
if (strlen(comment) > LIMIT_MESSAGE)
diff --git a/src/Daemon/CommLayerServerSocket.cpp b/src/Daemon/CommLayerServerSocket.cpp
index b54f9a6e..ab880fb2 100644
--- a/src/Daemon/CommLayerServerSocket.cpp
+++ b/src/Daemon/CommLayerServerSocket.cpp
@@ -145,7 +145,8 @@ void CCommLayerServerSocket::ProcessMessage(const std::string& pMessage, GIOChan
else if (!strncmp(pMessage.c_str(), MESSAGE_CREATE_REPORT, sizeof(MESSAGE_CREATE_REPORT) - 1))
{
// std::string UUID = pMessage.substr(sizeof(MESSAGE_CREATE_REPORT) - 1);
-// map_crash_data_t crashReport = CreateReport(UUID, UID);
+// map_crash_data_t crashReport;
+// CreateReport(UUID, UID, crashReport);
//use CreateReportThread instead of CreateReport?
// std::string message = MESSAGE_CREATE_REPORT + crash_report_to_string(crashReport);
// Send(message, pSource);
diff --git a/src/Daemon/CrashWatcher.cpp b/src/Daemon/CrashWatcher.cpp
index 80d8cd47..93365f3b 100644
--- a/src/Daemon/CrashWatcher.cpp
+++ b/src/Daemon/CrashWatcher.cpp
@@ -57,12 +57,11 @@ vector_map_crash_data_t GetCrashInfos(const char *pUID)
unsigned int ii;
for (ii = 0; ii < UUIDsUIDs.size(); ii++)
{
- mw_result_t res;
- map_crash_data_t info;
const char *uuid = UUIDsUIDs[ii].first.c_str();
const char *uid = UUIDsUIDs[ii].second.c_str();
- res = FillCrashInfo(uuid, uid, info);
+ map_crash_data_t info;
+ mw_result_t res = FillCrashInfo(uuid, uid, info);
switch (res)
{
case MW_OK:
@@ -96,18 +95,18 @@ vector_map_crash_data_t GetCrashInfos(const char *pUID)
* StartJob dbus call already did all the processing, and we just retrieve
* the result from dump directory, which is fast.
*/
-map_crash_data_t CreateReport(const char* pUUID, const char* pUID, int force)
+void CreateReport(const char* pUUID, const char* pUID, int force, map_crash_data_t& crashReport)
{
/* FIXME: starting from here, any shared data must be protected with a mutex.
* For example, CreateCrashReport does:
* g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str());
* which is unsafe wrt concurrent updates to g_pPluginManager state.
*/
- map_crash_data_t crashReport;
mw_result_t res = CreateCrashReport(pUUID, pUID, force, crashReport);
switch (res)
{
case MW_OK:
+ VERB2 log_map_crash_data(crashReport, "crashReport");
break;
case MW_IN_DB_ERROR:
error_msg("Can't find crash with UUID %s in database", pUUID);
@@ -120,7 +119,6 @@ map_crash_data_t CreateReport(const char* pUUID, const char* pUID, int force)
DeleteDebugDump(pUUID, pUID);
break;
}
- return crashReport;
}
typedef struct thread_data_t {
@@ -140,7 +138,8 @@ static void* create_report(void* arg)
try
{
log("Creating report...");
- map_crash_data_t crashReport = CreateReport(thread_data->UUID, thread_data->UID, thread_data->force);
+ map_crash_data_t crashReport;
+ CreateReport(thread_data->UUID, thread_data->UID, thread_data->force, crashReport);
g_pCommLayer->JobDone(thread_data->peer, thread_data->UUID);
}
catch (CABRTException& e)
diff --git a/src/Daemon/CrashWatcher.h b/src/Daemon/CrashWatcher.h
index 1e672b96..31b72e08 100644
--- a/src/Daemon/CrashWatcher.h
+++ b/src/Daemon/CrashWatcher.h
@@ -50,7 +50,7 @@ class CCrashWatcher
vector_map_crash_data_t GetCrashInfos(const char *pUID);
int CreateReportThread(const char* pUUID, const char* pUID, int force, const char* pSender);
-map_crash_data_t CreateReport(const char* pUUID, const char* pUID, int force);
+void CreateReport(const char* pUUID, const char* pUID, int force, map_crash_data_t&);
int DeleteDebugDump(const char *pUUID, const char *pUID);
void DeleteDebugDump_by_dir(const char *dump_dir);
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
index c7acffc3..83b1ceef 100644
--- a/src/Daemon/Daemon.cpp
+++ b/src/Daemon/Daemon.cpp
@@ -328,7 +328,7 @@ static void FindNewDumps(const char* pPath)
{
case MW_OK:
VERB1 log("Saving %s into database", itt->c_str());
- RunActionsAndReporters(crashinfo[CD_MWDDD][CD_CONTENT].c_str());
+ RunActionsAndReporters(get_crash_data_item_content(crashinfo, CD_DUMPDIR).c_str());
break;
case MW_IN_DB:
VERB1 log("%s is already saved in database", itt->c_str());
@@ -479,14 +479,14 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
try
{
std::string fullname = concat_path_file(DEBUG_DUMPS_DIR, name);
- map_crash_data_t crashinfo;
//todo: rename SaveDebugDump to ???? it does not save crashinfo, it FETCHES crashinfo
+ map_crash_data_t crashinfo;
mw_result_t res = SaveDebugDump(fullname.c_str(), crashinfo);
switch (res)
{
case MW_OK:
log("New crash, saving");
- RunActionsAndReporters(crashinfo[CD_MWDDD][CD_CONTENT].c_str());
+ RunActionsAndReporters(get_crash_data_item_content(crashinfo, CD_DUMPDIR).c_str());
/* Fall through */
case MW_REPORTED:
case MW_OCCURED:
@@ -494,8 +494,8 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
if (res != MW_OK)
log("Already saved crash, just sending dbus signal");
- const char *analyzer = crashinfo[CD_MWANALYZER][CD_CONTENT].c_str();
- const char *uid_str = crashinfo[CD_UID][CD_CONTENT].c_str();
+ const char *analyzer = get_crash_data_item_content(crashinfo, FILENAME_ANALYZER).c_str();
+ const char *uid_str = get_crash_data_item_content(crashinfo, FILENAME_UID).c_str();
/* Autoreport it if configured to do so */
if (analyzer_has_AutoReportUIDs(analyzer, uid_str))
@@ -503,7 +503,7 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
VERB1 log("Reporting the crash automatically");
map_crash_data_t crash_report;
mw_result_t crash_result = CreateCrashReport(
- crashinfo[CD_UUID][CD_CONTENT].c_str(),
+ get_crash_data_item_content(crashinfo, CD_UUID).c_str(),
uid_str, /*force:*/ 0, crash_report
);
if (crash_result == MW_OK)
@@ -525,7 +525,7 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
/* Send dbus signal */
if (analyzer_has_InformAllUsers(analyzer))
uid_str = NULL;
- g_pCommLayer->Crash(crashinfo[CD_PACKAGE][CD_CONTENT].c_str(), uid_str);
+ g_pCommLayer->Crash(get_crash_data_item_content(crashinfo, FILENAME_PACKAGE).c_str(), uid_str);
break;
}
case MW_BLACKLISTED:
diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp
index a2b20e68..9abb737b 100644
--- a/src/Daemon/MiddleWare.cpp
+++ b/src/Daemon/MiddleWare.cpp
@@ -148,37 +148,12 @@ static void load_crash_data_from_debug_dump(CDebugDump& dd, map_crash_data_t& da
dd.LoadText(short_name.c_str(), content);
free(text);
- if (short_name == FILENAME_ARCHITECTURE
- || short_name == FILENAME_KERNEL
- || short_name == FILENAME_PACKAGE
- || short_name == FILENAME_COMPONENT
- || short_name == FILENAME_RELEASE
- || short_name == FILENAME_EXECUTABLE
- ) {
- add_to_crash_data_ext(data,
- short_name.c_str(),
- CD_TXT,
- CD_ISNOTEDITABLE,
- content.c_str()
- );
- continue;
- }
-
- if (short_name != FILENAME_UID
- && short_name != FILENAME_ANALYZER
- && short_name != FILENAME_TIME
- && short_name != FILENAME_DESCRIPTION
- && short_name != FILENAME_REPRODUCE
- && short_name != FILENAME_COMMENT
- ) {
- add_to_crash_data_ext(
- data,
- short_name.c_str(),
- CD_TXT,
- CD_ISEDITABLE,
- content.c_str()
- );
- }
+ add_to_crash_data_ext(data,
+ short_name.c_str(),
+ CD_TXT,
+ is_editable_file(short_name.c_str()) ? CD_ISEDITABLE : CD_ISNOTEDITABLE,
+ content.c_str()
+ );
}
}
@@ -190,16 +165,19 @@ static void load_crash_data_from_debug_dump(CDebugDump& dd, map_crash_data_t& da
*/
static void DebugDumpToCrashReport(const char *pDebugDumpDir, map_crash_data_t& pCrashData)
{
+ VERB3 log(" DebugDumpToCrashReport('%s')", pDebugDumpDir);
+
CDebugDump dd;
dd.Open(pDebugDumpDir);
- if (!dd.Exist(FILENAME_ARCHITECTURE)
- || !dd.Exist(FILENAME_KERNEL)
- || !dd.Exist(FILENAME_PACKAGE)
- || !dd.Exist(FILENAME_COMPONENT)
- || !dd.Exist(FILENAME_RELEASE)
- || !dd.Exist(FILENAME_EXECUTABLE)
- ) {
- throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): One or more of important file(s) are missing");
+
+ const char *const *v = must_have_files;
+ while (*v)
+ {
+ if (!dd.Exist(*v))
+ {
+ throw CABRTException(EXCEP_ERROR, "DebugDumpToCrashReport(): important file '%s' is missing", *v);
+ }
+ v++;
}
load_crash_data_from_debug_dump(dd, pCrashData);
@@ -245,7 +223,7 @@ static std::string GetGlobalUUID(const char *pAnalyzer,
* @param pAnalyzer A name of an analyzer plugin.
* @param pDebugDumpPath A debugdump dir containing all necessary data.
*/
-static void CreateReport(const char *pAnalyzer,
+static void run_analyser_CreateReport(const char *pAnalyzer,
const char *pDebugDumpDir,
int force)
{
@@ -278,63 +256,56 @@ mw_result_t CreateCrashReport(const char *pUUID,
return MW_IN_DB_ERROR;
}
+ mw_result_t r = MW_OK;
try
{
- CDebugDump dd;
- std::string analyzer;
- std::string comment;
- std::string reproduce = "1.\n2.\n3.\n";
-
- VERB3 log(" LoadText(FILENAME_ANALYZER,'%s')", row.m_sDebugDumpDir.c_str());
- dd.Open(row.m_sDebugDumpDir.c_str());
- dd.LoadText(FILENAME_ANALYZER, analyzer);
- if (dd.Exist(FILENAME_COMMENT))
{
- dd.LoadText(FILENAME_COMMENT, comment);
+ CDebugDump dd;
+ dd.Open(row.m_sDebugDumpDir.c_str());
+ load_crash_data_from_debug_dump(dd, pCrashData);
}
- if (dd.Exist(FILENAME_REPRODUCE))
- {
- dd.LoadText(FILENAME_REPRODUCE, reproduce);
- }
- dd.Close();
- VERB3 log(" CreateReport('%s')", analyzer.c_str());
- CreateReport(analyzer.c_str(), row.m_sDebugDumpDir.c_str(), force);
+ std::string analyzer = get_crash_data_item_content(pCrashData, FILENAME_ANALYZER);
+
+ // TODO: explain what run_analyser_CreateReport and RunAnalyzerActions are expected to do.
+ // Do they potentially add more files to dump dir?
+ // Why we calculate dup_hash after run_analyser_CreateReport but before RunAnalyzerActions?
+ // Why do we reload dump dir's data via DebugDumpToCrashReport?
- std::string gUUID = GetGlobalUUID(analyzer.c_str(), row.m_sDebugDumpDir.c_str());
- VERB3 log(" GetGlobalUUID:'%s'", gUUID.c_str());
+ VERB3 log(" run_analyser_CreateReport('%s')", analyzer.c_str());
+ run_analyser_CreateReport(analyzer.c_str(), row.m_sDebugDumpDir.c_str(), force);
+
+ std::string dup_hash = GetGlobalUUID(analyzer.c_str(), row.m_sDebugDumpDir.c_str());
+ VERB3 log(" DUPHASH:'%s'", dup_hash.c_str());
VERB3 log(" RunAnalyzerActions('%s','%s')", analyzer.c_str(), row.m_sDebugDumpDir.c_str());
RunAnalyzerActions(analyzer.c_str(), row.m_sDebugDumpDir.c_str());
- VERB3 log(" DebugDumpToCrashReport");
+
DebugDumpToCrashReport(row.m_sDebugDumpDir.c_str(), pCrashData);
- add_to_crash_data_ext(pCrashData, CD_UUID , CD_TXT, CD_ISNOTEDITABLE, gUUID.c_str() );
- add_to_crash_data_ext(pCrashData, CD_MWANALYZER, CD_SYS, CD_ISNOTEDITABLE, analyzer.c_str() );
- add_to_crash_data_ext(pCrashData, CD_MWUID , CD_SYS, CD_ISNOTEDITABLE, pUID );
- add_to_crash_data_ext(pCrashData, CD_MWUUID , CD_SYS, CD_ISNOTEDITABLE, pUUID );
- add_to_crash_data_ext(pCrashData, CD_COMMENT , CD_TXT, CD_ISEDITABLE , comment.c_str() );
- add_to_crash_data_ext(pCrashData, CD_REPRODUCE , CD_TXT, CD_ISEDITABLE , reproduce.c_str());
+ add_to_crash_data_ext(pCrashData, CD_DUPHASH, CD_TXT, CD_ISNOTEDITABLE, dup_hash.c_str());
+ add_to_crash_data_ext(pCrashData, CD_UUID , CD_SYS, CD_ISNOTEDITABLE, pUUID);
}
catch (CABRTException& e)
{
+ r = MW_CORRUPTED;
error_msg("%s", e.what());
if (e.type() == EXCEP_DD_OPEN)
{
- return MW_ERROR;
+ r = MW_ERROR;
}
- if (e.type() == EXCEP_DD_LOAD)
+ else if (e.type() == EXCEP_DD_LOAD)
{
- return MW_FILE_ERROR;
+ r = MW_FILE_ERROR;
}
- if (e.type() == EXCEP_PLUGIN)
+ else if (e.type() == EXCEP_PLUGIN)
{
- return MW_PLUGIN_ERROR;
+ r = MW_PLUGIN_ERROR;
}
- return MW_CORRUPTED;
}
- return MW_OK;
+ VERB3 log("CreateCrashReport() returns %d", r);
+ return r;
}
void RunAction(const char *pActionDir,
@@ -391,88 +362,70 @@ void RunActionsAndReporters(const char *pDebugDumpDir)
}
-static bool CheckReport(const map_crash_data_t& pCrashData)
-{
- map_crash_data_t::const_iterator it_analyzer = pCrashData.find(CD_MWANALYZER);
- map_crash_data_t::const_iterator it_mwuid = pCrashData.find(CD_MWUID);
- map_crash_data_t::const_iterator it_mwuuid = pCrashData.find(CD_MWUUID);
-
- map_crash_data_t::const_iterator it_package = pCrashData.find(FILENAME_PACKAGE);
- map_crash_data_t::const_iterator it_architecture = pCrashData.find(FILENAME_ARCHITECTURE);
- map_crash_data_t::const_iterator it_kernel = pCrashData.find(FILENAME_KERNEL);
- map_crash_data_t::const_iterator it_component = pCrashData.find(FILENAME_COMPONENT);
- map_crash_data_t::const_iterator it_release = pCrashData.find(FILENAME_RELEASE);
- map_crash_data_t::const_iterator it_executable = pCrashData.find(FILENAME_EXECUTABLE);
-
- map_crash_data_t::const_iterator end = pCrashData.end();
-
- if (it_package == end)
- {
- return false;
- }
-
- // FIXME: bypass the test if it's kerneloops
- if (it_package->second[CD_CONTENT] == "kernel")
- return true;
-
- if (it_analyzer == end || it_mwuid == end ||
- it_mwuuid == end || /* it_package == end || */
- it_architecture == end || it_kernel == end ||
- it_component == end || it_release == end ||
- it_executable == end)
- {
- return false;
- }
-
- if (it_analyzer->second[CD_CONTENT] == "" || it_mwuid->second[CD_CONTENT] == "" ||
- it_mwuuid->second[CD_CONTENT] == "" || it_package->second[CD_CONTENT] == "" ||
- it_architecture->second[CD_CONTENT] == "" || it_kernel->second[CD_CONTENT] == "" ||
- it_component->second[CD_CONTENT] == "" || it_release->second[CD_CONTENT] == "" ||
- it_executable->second[CD_CONTENT] == "")
- {
- return false;
- }
-
- return true;
-}
-
-report_status_t Report(const map_crash_data_t& pCrashData,
+// We must not trust client_report here!
+// dbus handler passes it from user without checking
+report_status_t Report(const map_crash_data_t& client_report,
map_map_string_t& pSettings,
const char *pUID)
{
- report_status_t ret;
-
- /* dbus handler passes pCrashData from user without checking it */
-
- if (!CheckReport(pCrashData))
+ // Get ID fields
+ const char *UID = get_crash_data_item_content_or_NULL(client_report, FILENAME_UID);
+ const char *UUID = get_crash_data_item_content_or_NULL(client_report, CD_UUID);
+ if (!UID || !UUID) {
+ throw CABRTException(EXCEP_ERROR, "Report(): UID or UUID is missing in client's report data");
+ }
+
+ // Retrieve corresponding stored record
+ map_crash_data_t stored_report;
+ mw_result_t r = FillCrashInfo(UUID, UID, stored_report);
+ if (r != MW_OK)
+ return report_status_t();
+ const std::string& pDumpDir = get_crash_data_item_content(stored_report, CD_DUMPDIR);
+
+ // Save comment, "how to reproduce", backtrace
+ const char *comment = get_crash_data_item_content_or_NULL(client_report, FILENAME_COMMENT);
+ const char *reproduce = get_crash_data_item_content_or_NULL(client_report, FILENAME_REPRODUCE);
+ const char *backtrace = get_crash_data_item_content_or_NULL(client_report, FILENAME_BACKTRACE);
+ if (comment || reproduce || backtrace)
{
- throw CABRTException(EXCEP_ERROR, "Report(): Some of mandatory report data are missing.");
- }
-
- const std::string& analyzer = get_crash_data_item_content(pCrashData, CD_MWANALYZER);
- const std::string& UID = get_crash_data_item_content(pCrashData, CD_MWUID);
- const std::string& UUID = get_crash_data_item_content(pCrashData, CD_MWUUID);
- const std::string& packageNVR = get_crash_data_item_content(pCrashData, FILENAME_PACKAGE);
- std::string packageName = packageNVR.substr(0, packageNVR.rfind("-", packageNVR.rfind("-") - 1));
-
- // Save comment and "how to reproduce"
- map_crash_data_t::const_iterator it_comment = pCrashData.find(CD_COMMENT);
- map_crash_data_t::const_iterator it_reproduce = pCrashData.find(CD_REPRODUCE);
- if (it_comment != pCrashData.end() || it_reproduce != pCrashData.end())
- {
- std::string pDumpDir = getDebugDumpDir(UUID.c_str(), UID.c_str());
CDebugDump dd;
dd.Open(pDumpDir.c_str());
- if (it_comment != pCrashData.end())
+ if (comment)
{
- dd.SaveText(FILENAME_COMMENT, it_comment->second[CD_CONTENT].c_str());
+ dd.SaveText(FILENAME_COMMENT, comment);
+ add_to_crash_data_ext(stored_report, FILENAME_COMMENT, CD_TXT, CD_ISEDITABLE, comment);
}
- if (it_reproduce != pCrashData.end())
+ if (reproduce)
{
- dd.SaveText(FILENAME_REPRODUCE, it_reproduce->second[CD_CONTENT].c_str());
+ dd.SaveText(FILENAME_REPRODUCE, reproduce);
+ add_to_crash_data_ext(stored_report, FILENAME_REPRODUCE, CD_TXT, CD_ISEDITABLE, reproduce);
+ }
+ if (backtrace)
+ {
+ dd.SaveText(FILENAME_BACKTRACE, backtrace);
+ add_to_crash_data_ext(stored_report, FILENAME_BACKTRACE, CD_TXT, CD_ISEDITABLE, backtrace);
}
}
+ const std::string& analyzer = get_crash_data_item_content(stored_report, FILENAME_ANALYZER);
+
+ std::string dup_hash = GetGlobalUUID(analyzer.c_str(), pDumpDir.c_str());
+ VERB3 log(" DUPHASH:'%s'", dup_hash.c_str());
+ add_to_crash_data_ext(stored_report, CD_DUPHASH, CD_TXT, CD_ISNOTEDITABLE, dup_hash.c_str());
+
+ // Run reporters
+
+ VERB3 {
+ log("Run reporters");
+ log_map_crash_data(client_report, " client_report");
+ log_map_crash_data(stored_report, " stored_report");
+ }
+#define client_report client_report_must_not_be_used_below
+
+ map_crash_data_t::const_iterator its_PACKAGE = stored_report.find(FILENAME_PACKAGE);
+ std::string packageNVR = its_PACKAGE->second[CD_CONTENT];
+ std::string packageName = packageNVR.substr(0, packageNVR.rfind("-", packageNVR.rfind("-") - 1));
+
// analyzer with package name (CCpp:xorg-x11-app) has higher priority
std::string key = analyzer + ":" + packageName;
map_analyzer_actions_and_reporters_t::iterator end = s_mapAnalyzerActionsAndReporters.end();
@@ -484,6 +437,7 @@ report_status_t Report(const map_crash_data_t& pCrashData,
key = analyzer;
}
+ report_status_t ret;
std::string message;
if (keyPtr != end)
{
@@ -518,7 +472,7 @@ report_status_t Report(const map_crash_data_t& pCrashData,
}
#endif
map_plugin_settings_t plugin_settings = pSettings[plugin_name];
- std::string res = reporter->Report(pCrashData, plugin_settings, it_r->second.c_str());
+ std::string res = reporter->Report(stored_report, plugin_settings, it_r->second.c_str());
#if 0 /* Using ~user/.abrt/ is bad wrt security */
if (home != "")
@@ -544,10 +498,11 @@ report_status_t Report(const map_crash_data_t& pCrashData,
CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str());
database->Connect();
- database->SetReported(UUID.c_str(), UID.c_str(), message.c_str());
+ database->SetReported(UUID, UID, message.c_str());
database->DisConnect();
return ret;
+#undef client_report
}
/**
@@ -863,8 +818,7 @@ static mw_result_t SaveDebugDumpToDatabase(const char *pUUID,
return res;
}
-std::string getDebugDumpDir(const char *pUUID,
- const char *pUID)
+std::string getDebugDumpDir(const char *pUUID, const char *pUID)
{
CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str());
database->Connect();
@@ -936,10 +890,7 @@ mw_result_t FillCrashInfo(const char *pUUID,
{
CDebugDump dd;
dd.Open(row.m_sDebugDumpDir.c_str());
- dd.LoadText(FILENAME_EXECUTABLE, executable);
- dd.LoadText(FILENAME_PACKAGE, package);
- dd.LoadText(FILENAME_DESCRIPTION, description);
- dd.LoadText(FILENAME_ANALYZER, analyzer);
+ load_crash_data_from_debug_dump(dd, pCrashData);
}
catch (CABRTException& e)
{
@@ -947,18 +898,14 @@ mw_result_t FillCrashInfo(const char *pUUID,
return MW_ERROR;
}
- pCrashData.clear();
- add_to_crash_data(pCrashData, CD_EXECUTABLE , executable.c_str() );
- add_to_crash_data(pCrashData, CD_PACKAGE , package.c_str() );
- add_to_crash_data(pCrashData, CD_DESCRIPTION, description.c_str() );
- add_to_crash_data(pCrashData, CD_UUID , row.m_sUUID.c_str() );
- add_to_crash_data(pCrashData, CD_UID , row.m_sUID.c_str() );
- add_to_crash_data(pCrashData, CD_COUNT , row.m_sCount.c_str() );
- add_to_crash_data(pCrashData, CD_TIME , row.m_sTime.c_str() );
- add_to_crash_data(pCrashData, CD_REPORTED , row.m_sReported.c_str() );
- add_to_crash_data(pCrashData, CD_MESSAGE , row.m_sMessage.c_str() );
- add_to_crash_data(pCrashData, CD_MWDDD , row.m_sDebugDumpDir.c_str());
- add_to_crash_data(pCrashData, CD_MWANALYZER , analyzer.c_str() );
+ add_to_crash_data(pCrashData, CD_UUID , row.m_sUUID.c_str() );
+ add_to_crash_data(pCrashData, CD_COUNT , row.m_sCount.c_str() );
+ add_to_crash_data(pCrashData, CD_REPORTED , row.m_sReported.c_str() );
+ add_to_crash_data(pCrashData, CD_MESSAGE , row.m_sMessage.c_str() );
+ add_to_crash_data(pCrashData, CD_DUMPDIR , row.m_sDebugDumpDir.c_str());
+//TODO: why do we keep uid and time in DB and in dumpdir?!
+ add_to_crash_data(pCrashData, FILENAME_UID , row.m_sUID.c_str() );
+ add_to_crash_data(pCrashData, FILENAME_TIME , row.m_sTime.c_str() );
return MW_OK;
}
diff --git a/src/Gui/CCDump.py b/src/Gui/CCDump.py
index 96d036c4..1f290929 100644
--- a/src/Gui/CCDump.py
+++ b/src/Gui/CCDump.py
@@ -3,20 +3,55 @@ from datetime import datetime
from abrt_utils import _, init_logging, log, log1, log2
+# Should match CrashTypes.h!
CD_TYPE = 0
CD_EDITABLE = 1
CD_CONTENT = 2
+CD_SYS = "s"
+CD_BIN = "b"
+CD_TXT = "t"
+
+FILENAME_ARCHITECTURE = "architecture"
+FILENAME_KERNEL = "kernel"
+FILENAME_TIME = "time"
+FILENAME_UID = "uid"
+FILENAME_PACKAGE = "package"
+FILENAME_COMPONENT = "component"
+FILENAME_DESCRIPTION = "description"
+FILENAME_ANALYZER = "analyzer"
+FILENAME_RELEASE = "release"
+FILENAME_EXECUTABLE = "executable"
+FILENAME_REASON = "reason"
+FILENAME_COMMENT = "comment"
+FILENAME_REPRODUCE = "reproduce"
+FILENAME_RATING = "rating"
+FILENAME_CMDLINE = "cmdline"
+FILENAME_COREDUMP = "coredump"
+FILENAME_BACKTRACE = "backtrace"
+FILENAME_MEMORYMAP = "memorymap"
+FILENAME_KERNELOOPS = "kerneloops"
+
+CD_DUPHASH = "DUPHASH"
+CD_UUID = "UUID"
+CD_DUMPDIR = "DumpDir"
+CD_COUNT = "Count"
+CD_REPORTED = "Reported"
+CD_MESSAGE = "Message"
+
+# FIXME - create method or smth that returns type|editable|content
+
+
class Dump():
"""Class for mapping the debug dump to python object"""
def __init__(self):
self.UUID = None
- self.UID = None
+ self.uid = None
self.Count = None
- self.Executable = None
- self.Package = None
- self.Time = None
- self.Description = None
+ self.executable = None
+ self.package = None
+ self.time = None
+ self.description = None
self.Message = None
self.Reported = None
@@ -24,16 +59,16 @@ class Dump():
return self.UUID[CD_CONTENT]
def getUID(self):
- return self.UID[CD_CONTENT]
+ return self.uid[CD_CONTENT]
def getCount(self):
return self.Count[CD_CONTENT]
def getExecutable(self):
- return self.Executable[CD_CONTENT]
+ return self.executable[CD_CONTENT]
def getPackage(self):
- return self.Package[CD_CONTENT]
+ return self.package[CD_CONTENT]
def isReported(self):
return self.Reported[CD_CONTENT] == "1"
@@ -44,17 +79,17 @@ class Dump():
#return self.Message[CD_CONTENT].split('\n')
return self.Message[CD_CONTENT]
- def getTime(self,format):
+ def getTime(self, format):
#print format
if format:
try:
- return datetime.fromtimestamp(int(self.Time[CD_CONTENT])).strftime(format)
+ return datetime.fromtimestamp(int(self.time[CD_CONTENT])).strftime(format)
except Exception, e:
print e
- return int(self.Time[CD_CONTENT])
+ return int(self.time[CD_CONTENT])
def getPackageName(self):
- return self.Package[CD_CONTENT][:self.Package[CD_CONTENT].find("-")]
+ return self.package[CD_CONTENT][:self.package[CD_CONTENT].find("-")]
def getDescription(self):
- return self.Description[CD_CONTENT]
+ return self.description[CD_CONTENT]
diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py
index f67cd06a..8222c17c 100644
--- a/src/Gui/CCMainWindow.py
+++ b/src/Gui/CCMainWindow.py
@@ -229,23 +229,29 @@ class MainWindow():
# this should work until we keep the row object in the last position
dump = dumpsListStore.get_value(dumpsListStore.get_iter(path[0]), dumpsListStore.get_n_columns()-1)
#move this to Dump class
+ lReported = self.wTree.get_widget("lReported")
if dump.isReported():
+ report_label_raw = _("This crash has been reported:\n")
report_label = _("<b>This crash has been reported:</b>\n")
# plugin message follows, but at least in case of kerneloops,
# it is not informative (no URL to the report)
for message in dump.getMessage().split(';'):
- if message:
+ if message:
message_clean = message.strip()
if "http" in message_clean[0:5] or "file:///"[0:8] in message_clean:
report_message = "<a href=\"%s\">%s</a>" % (message_clean, message_clean)
else:
report_message = message_clean
report_label += "%s\n" % report_message
+ report_label_raw += "%s\n" % message_clean
log2("setting markup '%s'", report_label)
- self.wTree.get_widget("lReported").set_markup(report_label)
+ lReported.set_text(report_label_raw)
+ # Sometimes (!) set_markup() fails with
+ # "GtkWarning: Failed to set text from markup due to error parsing markup: Unknown tag 'a'"
+ # If it does, then set_text() above acts as a fallback
+ lReported.set_markup(report_label)
else:
- self.wTree.get_widget("lReported").set_markup(_("<b>Not reported!</b>"))
- lPackage = self.wTree.get_widget("lPackage")
+ lReported.set_markup(_("<b>Not reported!</b>"))
def on_bDelete_clicked(self, button, treeview):
dumpsListStore, path = self.dlist.get_selection().get_selected_rows()
@@ -303,14 +309,8 @@ class MainWindow():
try:
self.pBarWindow.show_all()
self.timer = gobject.timeout_add(100, self.progress_update_cb)
- # Old way: it needs to talk to daemon
- #reporters_settings = {}
- ## self.pluginlist = getPluginInfoList(self.ccdaemon, refresh=True)
- ## don't force refresh!
- #self.pluginlist = getPluginInfoList(self.ccdaemon)
- #for plugin in self.pluginlist.getReporterPlugins():
- # reporters_settings[str(plugin)] = plugin.Settings
- reporters_settings = getCurrentConfBackend().load_all()
+ pluginlist = getPluginInfoList(self.ccdaemon)
+ reporters_settings = pluginlist.getReporterPluginsSettings()
log2("Report(result,settings):")
log2(" result:%s", str(result))
# Careful, this will print reporters_settings["Password"] too
diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py
index bc970d2f..023cc6e5 100644
--- a/src/Gui/CCReporterDialog.py
+++ b/src/Gui/CCReporterDialog.py
@@ -11,16 +11,10 @@ from ABRTPlugin import PluginInfo
from PluginSettingsUI import PluginSettingsUI
from PluginList import getPluginInfoList
#from CCDumpList import getDumpList, DumpList
+from CCDump import * # FILENAME_xxx, CD_xxx
from abrt_utils import _, log, log1, log2
# FIXME - create method or smth that returns type|editable|content
-CD_TYPE = 0
-CD_EDITABLE = 1
-CD_CONTENT = 2
-
-CD_SYS = "s"
-CD_BIN = "b"
-CD_TXT = "t"
# response
REFRESH = -50
@@ -34,7 +28,7 @@ class ReporterDialog():
self.report = report
#Set the Glade file
# FIXME add to path
- builderfile = "%s%sreport.glade" % (sys.path[0],"/")
+ builderfile = "%s/report.glade" % sys.path[0]
self.builder = gtk.Builder()
self.builder.add_from_file(builderfile)
#Get the Main Window, and connect the "destroy" event
@@ -47,21 +41,20 @@ class ReporterDialog():
# comment textview
self.tvComment = self.builder.get_object("tvComment")
self.tvComment.connect("focus-in-event", self.on_comment_focus_cb)
- self.comment_changed = False
+ self.show_hint_comment = 1
# "how to reproduce" textview
self.tevHowToReproduce = self.builder.get_object("tevHowToReproduce")
- self.how_to_changed = False
self.builder.get_object("fErrors").hide()
self.builder.get_object("bLog").connect("clicked", self.show_log_cb, log)
self.builder.get_object("cbSendBacktrace").connect("toggled", self.on_send_backtrace_toggled)
self.allow_send()
self.hydrate()
-
+
def check_backtrace(self):
print "checking backtrace"
-
+
def warn_user(self, warnings):
# FIXME: show in lError
fErrors = self.builder.get_object("fErrors")
@@ -74,12 +67,12 @@ class ReporterDialog():
warning_lbl = "* %s" % warning
lErrors.set_label(warning_lbl)
fErrors.show_all()
-
+
def hide_warning(self):
fErrors = self.builder.get_object("fErrors")
lErrors = self.builder.get_object("lErrors")
fErrors.hide()
-
+
def allow_send(self):
self.hide_warning()
bSend = self.builder.get_object("bSend")
@@ -87,7 +80,7 @@ class ReporterDialog():
send = True
error_msgs = []
try:
- rating = self.report["rating"]
+ rating = self.report[FILENAME_RATING]
except:
rating = None
# active buttons acording to required fields
@@ -96,31 +89,32 @@ class ReporterDialog():
send = False
error_msgs.append(_("You must agree with submitting the backtrace."))
# we have both SendBacktrace and rating
- elif rating:
+ if rating:
try:
- package = self.report["package"][CD_CONTENT]
+ package = self.report[FILENAME_PACKAGE][CD_CONTENT]
# if we don't have package for some reason
except:
package = None
# not usable report
- if int(self.report["rating"][CD_CONTENT]) < 3:
+ if int(self.report[FILENAME_RATING][CD_CONTENT]) < 3:
if package:
error_msgs.append(_("Reporting disabled because the backtrace is unusable.\nPlease try to install debuginfo manually using command: <b>debuginfo-install %s</b> \nthen use Refresh button to regenerate the backtrace." % package[0:package.rfind('-',0,package.rfind('-'))]))
else:
error_msgs.append(_("The backtrace is unusable, you can't report this!"))
# probably usable 3
- elif int(self.report["rating"][CD_CONTENT]) < 4:
+ elif int(self.report[FILENAME_RATING][CD_CONTENT]) < 4:
error_msgs.append(_("The backtrace is incomplete, please make sure you provide good steps to reproduce."))
-
+
if error_msgs:
self.warn_user(error_msgs)
bSend.set_sensitive(send)
-
+
def on_send_backtrace_toggled(self, toggle_button):
self.allow_send()
-
+
def show_log_cb(self, widget, log):
show_log(log, parent=self.window)
+
# this callback is called when user press Cancel or Report button in Report dialog
def on_response(self, dialog, response_id, daemon):
# the button has been pressed (probably)
@@ -136,9 +130,10 @@ class ReporterDialog():
model[path][3] = not model[path][3]
def on_comment_focus_cb(self, widget, event):
- if not self.comment_changed:
+ if self.show_hint_comment:
+ # clear "hint" text by supplying a fresh, empty TextBuffer
widget.set_buffer(gtk.TextBuffer())
- self.comment_changed = True
+ self.show_hint_comment = 0
def on_config_plugin_clicked(self, button, plugin, image):
ui = PluginSettingsUI(plugin, parent=self.window)
@@ -204,66 +199,81 @@ class ReporterDialog():
if len(text) > label_widget.get_max_width_chars():
label_widget.set_tooltip_text(text)
label_widget.set_text(text)
-
+
def hydrate(self):
self.editable = []
+ self.old_comment = ""
+ self.old_how_to_reproduce = ""
for item in self.report:
- if item == "backtrace":
+ try:
+ log2("report[%s]:%s/%s/%s", item, self.report[item][0], self.report[item][1], self.report[item][2][0:20])
+ except:
+ pass
+
+ if item == FILENAME_BACKTRACE:
buff = gtk.TextBuffer()
tvBacktrace = self.builder.get_object("tvBacktrace")
buff.set_text(self.report[item][CD_CONTENT])
tvBacktrace.set_buffer(buff)
continue
- if item == "Comment":
- buff = gtk.TextBuffer()
- comment = _("Brief description how to reproduce this or what you did...")
+
+ if item == FILENAME_COMMENT:
try:
if self.report[item][CD_CONTENT]:
- comment = self.report[item][CD_CONTENT]
- self.comment_changed = True
+ self.old_comment = self.report[item][CD_CONTENT]
except Exception, e:
pass
-
- buff.set_text(comment)
-
- self.tvComment.set_buffer(buff)
continue
- if item == "How to reproduce":
- buff = gtk.TextBuffer()
- how_to_reproduce = _("")
+
+ if item == FILENAME_REPRODUCE:
try:
if self.report[item][CD_CONTENT]:
- how_to_reproduce = self.report[item][CD_CONTENT]
- self.how_to_changed = True
+ self.old_how_to_reproduce = self.report[item][CD_CONTENT]
except Exception, e:
pass
+ continue
- buff.set_text(how_to_reproduce)
+ if self.report[item][CD_TYPE] == CD_SYS:
+ continue
- self.tevHowToReproduce.set_buffer(buff)
+ # item name 0| value 1| editable? 2| toggled? 3| visible?(attachment)4
+ # FIXME: handle editable fields
+ if self.report[item][CD_TYPE] == CD_BIN:
+ self.builder.get_object("fAttachment").show()
+ vbAttachments = self.builder.get_object("vbAttachments")
+ toggle = gtk.CheckButton(self.report[item][CD_CONTENT])
+ vbAttachments.pack_start(toggle)
+ # bind item to checkbox
+ toggle.item = item
+ toggle.show()
continue
- if self.report[item][CD_TYPE] != CD_SYS:
- # item name 0| value 1| editable? 2| toggled? 3| visible?(attachment)4
- # FIXME: handle editable fields
- if self.report[item][CD_TYPE] == CD_BIN:
- self.builder.get_object("fAttachment").show()
- vbAttachments = self.builder.get_object("vbAttachments")
- toggle = gtk.CheckButton(self.report[item][CD_CONTENT])
- vbAttachments.pack_start(toggle)
- # bind item to checkbox
- toggle.item = item
- toggle.show()
- continue
- item_label = self.builder.get_object("l%s" % item)
- if item_label:
- self.set_label(item_label, self.report[item][CD_CONTENT])
- else:
- # no widget to show this item
- # probably some new item need to adjust the GUI!
- # FIXME: add some window+button to show all the info
- # in raw form (smth like the old report dialog)
- pass
+ # It must be CD_TXT field
+ item_label = self.builder.get_object("l%s" % item)
+ if item_label:
+ self.set_label(item_label, self.report[item][CD_CONTENT])
+ else:
+ # no widget to show this item
+ # probably some new item need to adjust the GUI!
+ # FIXME: add some window+button to show all the info
+ # in raw form (smth like the old report dialog)
+ pass
+ #end for
+
+ buff = gtk.TextBuffer()
+ self.show_hint_comment = (self.old_comment == "")
+ if self.show_hint_comment:
+ buff.set_text(_("Brief description how to reproduce this or what you did..."))
+ else:
+ buff.set_text(self.old_comment)
+ self.tvComment.set_buffer(buff)
+
+ buff = gtk.TextBuffer()
+ if self.old_how_to_reproduce == "":
+ buff.set_text("1.\n2.\n3.\n")
+ else:
+ buff.set_text(self.old_how_to_reproduce)
+ self.tevHowToReproduce.set_buffer(buff)
def dehydrate(self):
# handle attachments
@@ -271,23 +281,22 @@ class ReporterDialog():
for attachment in vbAttachments.get_children():
#print "%s file %s" % (["not sending","sending"][attachment.get_active()], attachment.get_label())
del self.report[attachment.item]
-
+
# handle comment
- if self.comment_changed:
- buff = self.tvComment.get_buffer()
- self.report["Comment"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())]
- else:
- del self.report["Comment"]
+ buff = self.tvComment.get_buffer()
+ text = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
+ if self.old_comment != text:
+ self.report[FILENAME_COMMENT] = [CD_TXT, 'y', text]
# handle how to reproduce
- if self.how_to_changed:
- buff = self.tevHowToReproduce.get_buffer()
- self.report["How to reproduce"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())]
- else:
- del self.report["How to reproduce"]
+ buff = self.tevHowToReproduce.get_buffer()
+ text = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
+ if self.old_how_to_reproduce != text:
+ self.report[FILENAME_REPRODUCE] = [CD_TXT, 'y', text]
#handle backtrace
tev_backtrace = self.builder.get_object("tvBacktrace")
buff = tev_backtrace.get_buffer()
- self.report["backtrace"] = [CD_TXT, 'y', buff.get_text(buff.get_start_iter(),buff.get_end_iter())]
+ text = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
+ self.report[FILENAME_BACKTRACE] = [CD_TXT, 'y', text]
def check_report(self):
# FIXME: check the report for passwords and some other potentially
@@ -299,4 +308,3 @@ class ReporterDialog():
result = self.window.run()
self.window.destroy()
return (result, self.report)
-
diff --git a/src/Gui/CC_gui_functions.py b/src/Gui/CC_gui_functions.py
index a9c47faf..e2260210 100644
--- a/src/Gui/CC_gui_functions.py
+++ b/src/Gui/CC_gui_functions.py
@@ -56,9 +56,14 @@ def gui_report_dialog ( report_status_dict, parent_dialog,
status_hbox.pack_start(plugin_label, expand=False)
status_hbox.pack_start(status_label, expand=False)
# 0 means not succesfull
- if report_status_dict[plugin][0] == '0':
- status_label.set_markup("<span foreground='red'>%s</span>" % report_status_dict[plugin][1])
- elif report_status_dict[plugin][0] == '1':
+ #if report_status_dict[plugin][0] == '0':
+ # this first one is actually a fallback to set at least
+ # a raw text in case when set_markup() fails
+ status_label.set_text(report_status_dict[plugin][1])
+ status_label.set_markup("<span foreground='red'>%s</span>" % report_status_dict[plugin][1])
+ # if the report was not succesful then this won't pass so this runs only
+ # if report succeds and gets overwriten by the status message
+ if report_status_dict[plugin][0] == '1':
if "http" in report_status_dict[plugin][1][0:4] or "file://" in report_status_dict[plugin][1][0:7]:
status_label.set_markup("<a href=\"%s\">%s</a>" % (report_status_dict[plugin][1], report_status_dict[plugin][1]))
# FIXME: make a new branch for rawhide with gtk 2.17 and remove this
diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py
index d2232bbc..82759ae3 100644
--- a/src/Gui/PluginList.py
+++ b/src/Gui/PluginList.py
@@ -38,6 +38,11 @@ class PluginInfoList(list):
def getReporterPlugins(self):
return [x for x in self if x["Enabled"] == 'yes' and x["Type"] == 'Reporter']
+ def getReporterPluginsSettings(self):
+ reporters_settings = {}
+ for plugin in self.getReporterPlugins():
+ reporters_settings[str(plugin)] = plugin.Settings
+ return reporters_settings
__PFList = None