1 /* bug-buddy bug submitting program
3 * Copyright (C) 2001 Jacob Berkman
4 * Copyright 2001 Ximian, Inc.
6 * Author: jacob berkman <jacob@bug-buddy.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
24 #include "bug-buddy.h"
25 #include "distribution.h"
28 #include <sys/types.h>
35 #include <glib/gi18n.h>
37 #include <bonobo/bonobo-exception.h>
38 #include <bonobo-activation/bonobo-activation.h>
40 #include <libxml/tree.h>
41 #include <libxml/parser.h>
42 #include <libxml/xmlmemory.h>
44 #include <libsoup/soup.h>
47 #define APPLET_REQUIREMENTS \
48 "has_all (repo_ids, ['IDL:Bonobo/Control:1.0'," \
49 " 'IDL:GNOME/Vertigo/PanelAppletShell:1.0']) && " \
50 "defined (panel:icon)"
52 #define DESKTOP_ENTRY "Desktop Entry"
53 #define DESKTOP_NAME "Name"
54 #define DESKTOP_COMMENT "Comment"
55 #define DESKTOP_ICON "Icon"
56 #define DESKTOP_EXEC "Exec"
58 #define BUGZILLA_BUGZILLA "X-GNOME-Bugzilla-Bugzilla"
59 #define BUGZILLA_PRODUCT "X-GNOME-Bugzilla-Product"
60 #define BUGZILLA_COMPONENT "X-GNOME-Bugzilla-Component"
61 #define BUGZILLA_EMAIL "X-GNOME-Bugzilla-Email"
62 #define BUGZILLA_VERSION "X-GNOME-Bugzilla-Version"
63 #define BUGZILLA_OTHER_BINARIES "X-GNOME-Bugzilla-OtherBinaries"
64 #define BUGZILLA_EXTRA_INFO_SCRIPT "X-GNOME-Bugzilla-ExtraInfoScript"
66 #define BA_BUGZILLA_BUGZILLA "bugzilla:bugzilla"
67 #define BA_BUGZILLA_PRODUCT "bugzilla:product"
68 #define BA_BUGZILLA_COMPONENT "bugzilla:component"
69 #define BA_BUGZILLA_VERSION "bugzilla:version"
70 #define BA_BUGZILLA_OTHER_BINARIES "bugzilla:other_binaries"
71 #define BA_BUGZILLA_EXTRA_INFO_SCRIPT "bugzilla:extra_info_script"
74 add_bugzilla_application (GHashTable
*hash
,
80 const char *component
,
84 const char *other_programs
,
85 const char *extra_info_script
)
87 BugzillaApplication
*app
;
91 app
= g_new0 (BugzillaApplication
, 1);
93 app
->name
= g_strdup (name
);
94 app
->cname
= g_strdup (cname
);
95 app
->comment
= g_strdup (comment
);
96 app
->icon
= g_strdup (icon
);
97 app
->bugzilla
= g_strdup (bugzilla
);
98 app
->product
= g_strdup (product
);
99 app
->component
= g_strdup (component
);
100 app
->version
= g_strdup (version
);
101 app
->extra_info_script
= g_strdup (extra_info_script
);
104 g_shell_parse_argv (program
, &i
, &programv
, NULL
);
107 s
= strrchr (programv
[0], G_DIR_SEPARATOR
);
108 s
= s
? s
+1 : programv
[0];
110 g_hash_table_insert (hash
, g_strdup (s
), app
);
116 g_strfreev (programv
);
119 if (other_programs
) {
120 programv
= g_strsplit (other_programs
, ";", -1);
121 for (i
=0; programv
[i
]; i
++) {
123 g_hash_table_insert (hash
, g_strdup (programv
[i
]), app
);
125 g_strfreev (programv
);
130 application_free (BugzillaApplication
*app
)
133 if (app
->ref_count
> 0)
138 g_free (app
->comment
);
140 g_free (app
->bugzilla
);
141 g_free (app
->product
);
142 g_free (app
->component
);
143 g_free (app
->version
);
144 g_free (app
->extra_info_script
);
151 static const GSList
*
152 get_i18n_slist (void)
154 const char * const *langs
;
156 static GSList
*langs_gslist
= NULL
;
161 langs
= g_get_language_names ();
162 for (i
= 0; langs
[i
] != 0; ++i
) {
163 langs_gslist
= g_slist_append (langs_gslist
, (gpointer
) langs
[i
]);
170 load_applets (GHashTable
*hash
)
172 Bonobo_ServerInfoList
*info_list
;
173 Bonobo_ServerInfo
*info
;
174 CORBA_Environment ev
;
179 CORBA_exception_init (&ev
);
180 info_list
= bonobo_activation_query (APPLET_REQUIREMENTS
, NULL
, &ev
);
181 if (BONOBO_EX (&ev
)) {
182 g_warning ("Applet list query failed: %s", BONOBO_EX_REPOID (&ev
));
183 CORBA_exception_free (&ev
);
186 CORBA_exception_free (&ev
);
188 langs
= (GSList
*)get_i18n_slist ();
190 for (i
= 0; i
< info_list
->_length
; i
++) {
191 info
= info_list
->_buffer
+ i
;
192 if (!bonobo_server_info_prop_lookup (info
,
193 BA_BUGZILLA_BUGZILLA
,
198 name
= g_strdup (bonobo_server_info_prop_lookup (info
, "name", langs
));
200 for (l = applications; l; l = l->next) {
201 BugzillaApplication *app = l->data;
203 if (strcmp (app->name, name) == 0) {
205 name = g_strdup_printf (_("%s (Panel Applet)"), bonobo_server_info_prop_lookup (info, "name", langs));
211 add_bugzilla_application (hash
,
213 bonobo_server_info_prop_lookup (info
, "name", NULL
),
214 bonobo_server_info_prop_lookup (info
, "description", langs
),
215 bonobo_server_info_prop_lookup (info
, BA_BUGZILLA_BUGZILLA
, NULL
),
216 bonobo_server_info_prop_lookup (info
, BA_BUGZILLA_PRODUCT
, NULL
),
217 bonobo_server_info_prop_lookup (info
, BA_BUGZILLA_COMPONENT
, NULL
),
218 bonobo_server_info_prop_lookup (info
, BA_BUGZILLA_VERSION
, NULL
),
219 bonobo_server_info_prop_lookup (info
, "panel:icon", NULL
),
221 bonobo_server_info_prop_lookup (info
, BA_BUGZILLA_OTHER_BINARIES
, NULL
),
222 bonobo_server_info_prop_lookup (info
, BA_BUGZILLA_EXTRA_INFO_SCRIPT
, NULL
));
227 CORBA_free (info_list
);
231 add_bugzilla_application_from_desktop_file (GHashTable
*hash
,
232 const char *desktop_file_path
)
235 GError
*error
= NULL
;
245 char *other_binaries
;
246 char *extra_info_script
;
248 key_file
= g_key_file_new ();
249 g_key_file_load_from_file (key_file
, desktop_file_path
,
250 G_KEY_FILE_NONE
, &error
);
252 g_warning ("Couldn't load %s: %s", desktop_file_path
,
254 g_error_free (error
);
259 if (!g_key_file_has_group (key_file
, DESKTOP_ENTRY
) ||
260 !g_key_file_has_key (key_file
, DESKTOP_ENTRY
, BUGZILLA_BUGZILLA
, &error
)) {
261 g_key_file_free (key_file
);
263 g_error_free (error
);
267 name
= g_key_file_get_locale_string (key_file
, DESKTOP_ENTRY
, DESKTOP_NAME
, NULL
, NULL
);
268 cname
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, DESKTOP_NAME
, NULL
);
269 comment
= g_key_file_get_locale_string (key_file
, DESKTOP_ENTRY
, DESKTOP_COMMENT
, NULL
, NULL
);
270 bugzilla
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, BUGZILLA_BUGZILLA
, NULL
);
271 product
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, BUGZILLA_PRODUCT
, NULL
);
272 component
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, BUGZILLA_COMPONENT
, NULL
);
273 version
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, BUGZILLA_VERSION
, NULL
);
274 icon
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, DESKTOP_ICON
, NULL
);
275 exec
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, DESKTOP_EXEC
, NULL
);
276 other_binaries
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, BUGZILLA_OTHER_BINARIES
, NULL
);
277 extra_info_script
= g_key_file_get_string (key_file
, DESKTOP_ENTRY
, BUGZILLA_EXTRA_INFO_SCRIPT
, NULL
);
279 add_bugzilla_application (hash
,
300 g_free (other_binaries
);
301 g_free (extra_info_script
);
302 g_key_file_free (key_file
);
306 load_applications_from_dir (GHashTable
*hash
,
313 dir
= g_dir_open (path
, 0, NULL
);
317 while ((name
= g_dir_read_name (dir
))) {
318 if (g_main_context_pending (NULL
)) {
319 g_main_context_iteration (NULL
, FALSE
);
322 if (!g_str_has_suffix (name
, ".desktop")) {
326 desktop_file
= g_build_filename (path
, name
, NULL
);
327 add_bugzilla_application_from_desktop_file (hash
, desktop_file
);
328 g_free (desktop_file
);
335 get_all_directories (void)
338 const char * const *system_config_dirs
;
339 const char * const *system_data_dirs
;
342 dirs
= g_ptr_array_new ();
344 system_data_dirs
= g_get_system_data_dirs ();
345 for (i
= 0; system_data_dirs
[i
]; i
++) {
346 g_ptr_array_add (dirs
,
347 g_build_filename (system_data_dirs
[i
],
348 "applications", NULL
));
349 g_ptr_array_add (dirs
,
350 g_build_filename (system_data_dirs
[i
],
351 "gnome", "autostart", NULL
));
354 system_config_dirs
= g_get_system_config_dirs ();
355 for (i
= 0; system_config_dirs
[i
]; i
++) {
356 g_ptr_array_add (dirs
,
357 g_build_filename (system_config_dirs
[i
],
361 g_ptr_array_add (dirs
, NULL
);
363 return (char **) g_ptr_array_free (dirs
, FALSE
);
367 bugzilla_error_quark (void)
369 return g_quark_from_static_string ("bugzilla_error");
373 load_applications (void)
378 GHashTable
*program_to_application
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, (GDestroyNotify
) application_free
);
380 directories
= get_all_directories ();
381 for (i
= 0; directories
[i
] != NULL
; i
++)
382 load_applications_from_dir (program_to_application
, directories
[i
]);
383 g_strfreev (directories
);
385 load_applets (program_to_application
);
387 return program_to_application
;
391 bugzilla_search_for_package (gpointer key
, gpointer value
, const char *package
)
393 BugzillaApplication
*app
= (BugzillaApplication
*) value
;
395 if (!strcmp (app
->product
, package
))
403 bugzilla_parse_response (SoupMessage
*msg
, GError
**err
)
409 g_return_val_if_fail ((err
== NULL
|| *err
== NULL
), NULL
);
411 if (!SOUP_STATUS_IS_SUCCESSFUL (msg
->status_code
)) {
412 g_set_error (err
, BUGZILLA_ERROR
, BUGZILLA_ERROR_RECV_BAD_STATUS
,
413 _("HTTP Response returned bad status code %d"), msg
->status_code
);
417 if (!soup_xmlrpc_parse_method_response (msg
->response_body
->data
,
418 msg
->response_body
->length
,
422 if (G_VALUE_HOLDS_INT (&value
))
423 bugid
= g_value_get_int (&value
);
424 else if (G_VALUE_HOLDS_STRING (&value
))
425 url
= g_value_dup_string (&value
);
427 g_value_unset (&value
);
428 g_set_error (err
, BUGZILLA_ERROR
, BUGZILLA_ERROR_RECV_PARSE_FAILED
,
429 _("Unable to parse XML-RPC response\n\n%s"),
430 msg
->response_body
->data
);
433 g_value_unset (&value
);
435 return bugid
? g_strdup_printf ("%d", bugid
) : url
;
439 bugzilla_create_report (BugzillaApplication
*app
, int type
, GnomeVersionInfo
*gnome_version
,
440 const char *username
, const char *title
, const char *text
,
441 GtkBuilder
*ui
, GError
**err
)
443 SoupMessage
*message
;
451 g_return_val_if_fail (app
!= NULL
, NULL
);
452 g_return_val_if_fail (gnome_version
!= NULL
, NULL
);
453 g_return_val_if_fail (username
!= NULL
, NULL
);
454 g_return_val_if_fail (text
!= NULL
, NULL
);
455 g_return_val_if_fail (ui
!= NULL
, NULL
);
456 g_return_val_if_fail (err
== NULL
|| *err
== NULL
, NULL
);
458 /* FIXME: Hardcoded right now */
459 if (app
->bugzilla
== NULL
|| strcmp (app
->bugzilla
, "GNOME") != 0) {
460 g_set_error (err
, BUGZILLA_ERROR
, BUGZILLA_ERROR_SEND_NOTSUPPORTED_APP
,
461 _("Application does not track its bugs in the GNOME Bugzilla."));
465 if (!app
->product
|| !app
->component
) {
466 g_set_error (err
, BUGZILLA_ERROR
, BUGZILLA_ERROR_SEND_NOTSUPPORTED_APP
,
467 _("Product or component not specified."));
471 report
= soup_value_hash_new ();
473 soup_value_hash_insert (report
, "version", G_TYPE_STRING
,
474 app
->version
? app
->version
: "unspecified");
475 soup_value_hash_insert (report
, "product", G_TYPE_STRING
, app
->product
);
476 soup_value_hash_insert (report
, "component", G_TYPE_STRING
, app
->component
);
477 soup_value_hash_insert (report
, "gnome_version", G_TYPE_STRING
,
478 gnome_version
->gnome_platform
);
479 soup_value_hash_insert (report
, "reporter", G_TYPE_STRING
, username
);
481 os_version
= get_distro_name ();
482 soup_value_hash_insert (report
, "os_version", G_TYPE_STRING
, os_version
);
485 if (type
== BUG_TYPE_CRASH
) {
486 soup_value_hash_insert (report
, "priority", G_TYPE_STRING
, "High");
487 soup_value_hash_insert (report
, "bug_severity", G_TYPE_STRING
, "critical");
490 soup_value_hash_insert (report
, "short_desc", G_TYPE_STRING
, title
);
492 /* Skip UTF-8 control chars that are not valid in XML.*/
493 rv
= g_string_new (NULL
);
496 gchar
*next
= g_utf8_next_char (crt
);
497 gunichar uni
= g_utf8_get_char (crt
);
499 if (!g_unichar_iscntrl (uni
) || (uni
== '\n') || (uni
== '\t'))
500 g_string_append_len (rv
, crt
, next
- crt
);
505 soup_value_hash_insert (report
, "comment", G_TYPE_STRING
, rv
->str
);
506 g_string_free (rv
, TRUE
);
508 uri
= "http://bugzilla.gnome.org/bugbuddy.cgi";
510 message
= soup_xmlrpc_request_new (uri
, "BugBuddy.createBug",
511 G_TYPE_HASH_TABLE
, report
,
513 g_hash_table_destroy (report
);
514 if (message
== NULL
) {
515 g_set_error (err
, BUGZILLA_ERROR
, BUGZILLA_ERROR_SEND_ERROR
,
516 _("Unable to create XML-RPC message."));
520 /* FIXME: wrong User-Agent syntax. Should be "Bug-Buddy (VERSION)" */
521 user_agent
= g_strdup_printf ("Bug-Buddy: %s", VERSION
);
522 soup_message_headers_append (message
->request_headers
,
523 "User-Agent", user_agent
);