/* Capture child told us that an error has occurred while starting/running the capture. The buffer we're handed has *two* null-terminated strings in it - a primary message and a secondary message, one right after the other. The secondary message might be a null string. */ void capture_input_error_message(capture_session *cap_session, char *error_msg, char *secondary_error_msg) { gchar *safe_error_msg; gchar *safe_secondary_error_msg; g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"", error_msg, secondary_error_msg); g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING); safe_error_msg = simple_dialog_format_message(error_msg); if (*secondary_error_msg != '\0') { /* We have both primary and secondary messages. */ safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg); simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s", simple_dialog_primary_start(), safe_error_msg, simple_dialog_primary_end(), safe_secondary_error_msg); g_free(safe_secondary_error_msg); } else { /* We have only a primary message. */ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s", simple_dialog_primary_start(), safe_error_msg, simple_dialog_primary_end()); } g_free(safe_error_msg); /* the capture child will close the sync_pipe if required, nothing to do for now */ }
/* Capture child told us that an error has occurred while parsing a capture filter when starting/running the capture. */ void capture_input_cfilter_error_message(capture_session *cap_session, guint i, char *error_message) { capture_options *capture_opts = cap_session->capture_opts; dfilter_t *rfcode = NULL; gchar *safe_cfilter; gchar *safe_descr; gchar *safe_cfilter_error_msg; interface_options interface_opts; g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message); g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING); g_assert(i < capture_opts->ifaces->len); interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); safe_cfilter = simple_dialog_format_message(interface_opts.cfilter); safe_descr = simple_dialog_format_message(interface_opts.descr); safe_cfilter_error_msg = simple_dialog_format_message(error_message); /* Did the user try a display filter? */ if (dfilter_compile(interface_opts.cfilter, &rfcode) && rfcode != NULL) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%sInvalid capture filter \"%s\" for interface %s!%s\n" "\n" "That string looks like a valid display filter; however, it isn't a valid\n" "capture filter (%s).\n" "\n" "Note that display filters and capture filters don't have the same syntax,\n" "so you can't use most display filter expressions as capture filters.\n" "\n" "See the User's Guide for a description of the capture filter syntax.", simple_dialog_primary_start(), safe_cfilter, safe_descr, simple_dialog_primary_end(), safe_cfilter_error_msg); dfilter_free(rfcode); } else { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%sInvalid capture filter \"%s\" for interface %s!%s\n" "\n" "That string isn't a valid capture filter (%s).\n" "See the User's Guide for a description of the capture filter syntax.", simple_dialog_primary_start(), safe_cfilter, safe_descr, simple_dialog_primary_end(), safe_cfilter_error_msg); } g_free(safe_cfilter_error_msg); g_free(safe_descr); g_free(safe_cfilter); /* the capture child will close the sync_pipe if required, nothing to do for now */ }
/* * Alert box for an invalid display filter expression. * Assumes "dfilter_error_msg" has been set by "dfilter_compile()" to the * error message for the filter. * * XXX - should this have a "Help" button that pops up the display filter * help? */ void bad_dfilter_alert_box(const char *dftext) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n" "\n" "The filter expression \"%s\" isn't a valid display filter.\n" "See the help for a description of the display filter syntax.", simple_dialog_primary_start(), dfilter_error_msg, simple_dialog_primary_end(), dftext); }
/* display an update_info */ static void update_info_display(update_info_t *update_info) { GString *overview; overview = g_string_new(""); if(update_info->title) { g_string_append_printf(overview, "%s%s%s", simple_dialog_primary_start(), update_info->title, simple_dialog_primary_end()); } else { g_string_append_printf(overview, "%sComponent%s", simple_dialog_primary_start(), simple_dialog_primary_end()); } g_string_append(overview, "\n\n"); if(update_info->description) g_string_append_printf(overview, "%s\n\n", update_info->description); g_string_append_printf(overview, "Installed: %s\n", update_info->version_installed); if(update_info->version_recommended) g_string_append_printf(overview, "Recommended: %s\n", update_info->version_recommended); else g_string_append(overview, "Recommenced: unknown\n"); if(update_info->version_recommended && update_info->url) g_string_append_printf(overview, "From: %s\n", update_info->url); if(update_info->size) g_string_append_printf(overview, "Size: %s", update_info->size); simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, overview->str); g_string_free(overview, TRUE); }
void pixmap_save_cb(GtkWidget *w, gpointer pixmap_ptr _U_) { GtkWidget *save_as_w; #if GTK_CHECK_VERSION(2,22,0) surface_info_t *surface_info = g_object_get_data(G_OBJECT(w), "surface-info"); #else GdkPixmap *pixmap = g_object_get_data(G_OBJECT(w), "pixmap"); #endif GdkPixbuf *pixbuf; GdkPixbufFormat *pixbuf_format; GtkWidget *main_vb, *save_as_type_hb, *type_lb, *type_cm; GSList *file_formats,*ffp; GdkWindow *parent; gchar *format_name; guint format_index = 0; guint default_index = 0; gchar *filename, *file_type; GError *error = NULL; gboolean ret; GtkWidget *msg_dialog; #if GTK_CHECK_VERSION(2,22,0) pixbuf = gdk_pixbuf_get_from_surface (surface_info->surface, 0, 0, surface_info->width, surface_info->height); #else pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, NULL, 0, 0, 0, 0, -1, -1); #endif if(!pixbuf) { simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%sCould not get image from graph%s", simple_dialog_primary_start(), simple_dialog_primary_end()); return; } save_as_w = file_selection_new("Wireshark: Save Graph As ...", FILE_SELECTION_SAVE); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(save_as_w), TRUE); /* Container for each row of widgets */ main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE); file_selection_set_extra_widget(save_as_w, main_vb); gtk_widget_show(main_vb); save_as_type_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE); gtk_box_pack_start(GTK_BOX(main_vb), save_as_type_hb, FALSE, FALSE, 0); gtk_widget_show(save_as_type_hb); type_lb = gtk_label_new("File type: "); gtk_box_pack_start(GTK_BOX(save_as_type_hb), type_lb, FALSE, FALSE, 0); gtk_widget_show(type_lb); type_cm = gtk_combo_box_text_new(); gtk_box_pack_start(GTK_BOX(save_as_type_hb), type_cm, FALSE, FALSE, 0); /* List all of the file formats the gdk-pixbuf library supports */ file_formats = gdk_pixbuf_get_formats(); ffp = file_formats; while(ffp) { pixbuf_format = ffp->data; if (gdk_pixbuf_format_is_writable(pixbuf_format)) { format_name = gdk_pixbuf_format_get_name(pixbuf_format); gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(type_cm), format_name); if (!(g_ascii_strcasecmp(format_name, "png"))) default_index = format_index; format_index++; } ffp = g_slist_next(ffp); } g_slist_free(file_formats); gtk_combo_box_set_active(GTK_COMBO_BOX(type_cm), default_index); gtk_widget_show(type_cm); gtk_widget_show(save_as_w); window_present(save_as_w); parent = gtk_widget_get_parent_window(w); gdk_window_set_transient_for(gtk_widget_get_window(save_as_w), parent); /* * Loop until the user either selects a file or gives up. */ for (;;) { if (gtk_dialog_run(GTK_DIALOG(save_as_w)) != GTK_RESPONSE_ACCEPT) { /* They clicked "Cancel" or closed the dialog or.... */ window_destroy(save_as_w); return; } filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(save_as_w)); /* Perhaps the user specified a directory instead of a file. Check whether they did. */ if (test_for_directory(filename) == EISDIR) { /* It's a directory - set the file selection box to display that directory, and leave the selection box displayed. */ set_last_open_dir(filename); g_free(filename); file_selection_set_current_folder(save_as_w, get_last_open_dir()); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_as_w), ""); continue; } file_type = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(type_cm)); ret = gdk_pixbuf_save(pixbuf, filename, file_type, &error, NULL); g_free(filename); g_free(file_type); if (!ret) { msg_dialog = gtk_message_dialog_new(GTK_WINDOW(save_as_w), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", error->message); gtk_dialog_run(GTK_DIALOG(msg_dialog)); gtk_widget_destroy(msg_dialog); continue; } window_destroy(save_as_w); return; } }
/* open/merge the dnd file */ void dnd_open_file_cmd(gchar *cf_names_freeme) { int err; gchar *cf_name; int in_files; GString *dialog_text; int files_work; char **in_filenames; if (cf_names_freeme == NULL) return; /* DND_TARGET_URL: * The cf_name_freeme is a single string, containing one or more URI's, * terminated by CR/NL chars. The length of the whole field can be found * in the selection_data->length field. If it contains one file, simply open it, * If it contains more than one file, ask to merge these files. */ /* count the number of input files */ cf_name = cf_names_freeme; for(in_files = 0; (cf_name = strstr(cf_name, "\r\n")) != NULL; ) { cf_name += 2; in_files++; } if (in_files == 0) { g_free(cf_names_freeme); return; } in_filenames = g_malloc(sizeof(char*) * in_files); /* store the starts of the file entries in a gchar array */ cf_name = cf_names_freeme; in_filenames[0] = cf_name; for(files_work = 1; (cf_name = strstr(cf_name, "\r\n")) != NULL && files_work < in_files; ) { cf_name += 2; in_filenames[files_work] = cf_name; files_work++; } /* replace trailing CR NL simply with zeroes (in place), so we get valid terminated strings */ cf_name = cf_names_freeme; g_strdelimit(cf_name, "\r\n", '\0'); /* convert all filenames from URI to local filename (in place) */ for(files_work = 0; files_work < in_files; files_work++) { in_filenames[files_work] = dnd_uri2filename(in_filenames[files_work]); } if (in_files == 1) { /* open and read the capture file (this will close an existing file) */ if (cf_open(&cfile, in_filenames[0], FALSE, &err) == CF_OK) { /* XXX - add this to the menu if the read fails? */ cf_read(&cfile, FALSE); add_menu_recent_capture_file(in_filenames[0]); } else { /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */ } } else { /* build and show the info dialog */ dialog_text = g_string_sized_new(200); g_string_printf(dialog_text, "%sMerging the following files:%s\n\n", simple_dialog_primary_start(), simple_dialog_primary_end()); for(files_work = 0; files_work < in_files; files_work++) { g_string_append(dialog_text, in_filenames[files_work]); g_string_append(dialog_text, "\n"); } g_string_append(dialog_text, "\nThe packets in these files will be merged chronologically into a new temporary file."); simple_dialog(ESD_TYPE_CONFIRMATION, ESD_BTN_OK, "%s", dialog_text->str); g_string_free(dialog_text, TRUE); /* actually merge the files now */ dnd_merge_files(in_files, in_filenames); } g_free(in_filenames); g_free(cf_names_freeme); }
/* capture child closed its side of the pipe, do the required cleanup */ void capture_input_closed(capture_session *cap_session, gchar *msg) { capture_options *capture_opts = cap_session->capture_opts; int err; int packet_count_save; g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!"); g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING); if (msg != NULL) simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", msg); if(cap_session->state == CAPTURE_PREPARING) { /* We didn't start a capture; note that the attempt to start it failed. */ capture_callback_invoke(capture_cb_capture_failed, cap_session); } else { /* We started a capture; process what's left of the capture file if we were in "update list of packets in real time" mode, or process all of it if we weren't. */ if(capture_opts->real_time_mode) { cf_read_status_t status; /* Read what remains of the capture file. */ status = cf_finish_tail((capture_file *)cap_session->cf, &err); /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */ packet_count_save = cf_get_packet_count((capture_file *)cap_session->cf); /* Tell the GUI we are not doing a capture any more. Must be done after the cf_finish_tail(), so file lengths are correctly displayed */ capture_callback_invoke(capture_cb_capture_update_finished, cap_session); /* Finish the capture. */ switch (status) { case CF_READ_OK: if ((packet_count_save == 0) && !capture_opts->restart) { simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%sNo packets captured!%s\n" "\n" "As no data was captured, closing the %scapture file!\n" "\n" "\n" "Help about capturing can be found at:\n" "\n" " http://wiki.wireshark.org/CaptureSetup" #ifdef _WIN32 "\n\n" "Wireless (Wi-Fi/WLAN):\n" "Try to switch off promiscuous mode in the Capture Options!" #endif "", simple_dialog_primary_start(), simple_dialog_primary_end(), cf_is_tempfile((capture_file *)cap_session->cf) ? "temporary " : ""); cf_close((capture_file *)cap_session->cf); } break; case CF_READ_ERROR: /* Just because we got an error, that doesn't mean we were unable to read any of the file; we handle what we could get from the file. */ break; case CF_READ_ABORTED: /* Exit by leaving the main loop, so that any quit functions we registered get called. */ main_window_quit(); break; } } else { /* first of all, we are not doing a capture any more */ capture_callback_invoke(capture_cb_capture_fixed_finished, cap_session); /* this is a normal mode capture and if no error happened, read in the capture file data */ if(capture_opts->save_file != NULL) { capture_input_read_all(cap_session, cf_is_tempfile((capture_file *)cap_session->cf), cf_get_drops_known((capture_file *)cap_session->cf), cf_get_drops((capture_file *)cap_session->cf)); } } } if(capture_opts->show_info) capture_info_close(); cap_session->state = CAPTURE_STOPPED; /* if we couldn't open a capture file, there's nothing more for us to do */ if(capture_opts->save_file == NULL) { cf_close((capture_file *)cap_session->cf); return; } /* does the user wants to restart the current capture? */ if(capture_opts->restart) { capture_opts->restart = FALSE; ws_unlink(capture_opts->save_file); /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */ if(cf_is_tempfile((capture_file *)cap_session->cf)) { g_free(capture_opts->save_file); capture_opts->save_file = NULL; } /* ... and start the capture again */ if (capture_opts->ifaces->len == 0) { collect_ifaces(capture_opts); } /* close the currently loaded capture file */ cf_close((capture_file *)cap_session->cf); capture_start(capture_opts, cap_session); } else { /* We're not doing a capture any more, so we don't have a save file. */ g_free(capture_opts->save_file); capture_opts->save_file = NULL; } }
/* We've succeeded in doing a (non real-time) capture; try to read it into a new capture file */ static gboolean capture_input_read_all(capture_session *cap_session, gboolean is_tempfile, gboolean drops_known, guint32 drops) { capture_options *capture_opts = cap_session->capture_opts; int err; /* Capture succeeded; attempt to open the capture file. */ if (cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) { /* We're not doing a capture any more, so we don't have a save file. */ return FALSE; } /* Set the read filter to NULL. */ /* XXX - this is odd here; try to put it somewhere where it fits better */ cf_set_rfcode((capture_file *)cap_session->cf, NULL); /* Get the packet-drop statistics. XXX - there are currently no packet-drop statistics stored in libpcap captures, and that's what we're reading. At some point, we will add support in Wiretap to return packet-drop statistics for capture file formats that store it, and will make "cf_read()" get those statistics from Wiretap. We clear the statistics (marking them as "not known") in "cf_open()", and "cf_read()" will only fetch them and mark them as known if Wiretap supplies them, so if we get the statistics now, after calling "cf_open()" but before calling "cf_read()", the values we store will be used by "cf_read()". If a future libpcap capture file format stores the statistics, we'll put them into the capture file that we write, and will thus not have to set them here - "cf_read()" will get them from the file and use them. */ if (drops_known) { cf_set_drops_known((capture_file *)cap_session->cf, TRUE); /* XXX - on some systems, libpcap doesn't bother filling in "ps_ifdrop" - it doesn't even set it to zero - so we don't bother looking at it. Ideally, libpcap would have an interface that gave us several statistics - perhaps including various interface error statistics - and would tell us which of them it supplies, allowing us to display only the ones it does. */ cf_set_drops((capture_file *)cap_session->cf, drops); } /* read in the packet data */ switch (cf_read((capture_file *)cap_session->cf, FALSE)) { case CF_READ_OK: case CF_READ_ERROR: /* Just because we got an error, that doesn't mean we were unable to read any of the file; we handle what we could get from the file. */ break; case CF_READ_ABORTED: /* User wants to quit program. Exit by leaving the main loop, so that any quit functions we registered get called. */ main_window_nested_quit(); return FALSE; } /* if we didn't capture even a single packet, close the file again */ if(cf_get_packet_count((capture_file *)cap_session->cf) == 0 && !capture_opts->restart) { simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%sNo packets captured!%s\n" "\n" "As no data was captured, closing the %scapture file!\n" "\n" "\n" "Help about capturing can be found at:\n" "\n" " http://wiki.wireshark.org/CaptureSetup" #ifdef _WIN32 "\n\n" "Wireless (Wi-Fi/WLAN):\n" "Try to switch off promiscuous mode in the Capture Options!" #endif "", simple_dialog_primary_start(), simple_dialog_primary_end(), (cf_is_tempfile((capture_file *)cap_session->cf)) ? "temporary " : ""); cf_close((capture_file *)cap_session->cf); } return TRUE; }
gboolean filemanager_open_directory (const gchar *path) { #if defined(G_OS_WIN32) /* ShellExecute(...,"explore",...) needs path to be explicitly a directory; Otherwise 'explore' will fail if a file exists with a basename matching the provided directory path. (eg: wireshak-gtk2.exe exists in the same directory as a wireshark-gtk2 directory entry). */ gint ret; gchar *xpath; xpath = g_strconcat(path, g_str_has_suffix(path, "\\") ? "" : "\\", NULL); ret = (gint) ShellExecute (HWND_DESKTOP, _T("explore"), utf_8to16(xpath), NULL, NULL, SW_SHOWNORMAL); g_free(xpath); return (ret > 32); #elif defined(HAVE_OS_X_FRAMEWORKS) CFStringRef path_CFString; CFURLRef path_CFURL; OSStatus status; path_CFString = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8); if (path_CFString == NULL) return (FALSE); path_CFURL = CFURLCreateWithFileSystemPath(NULL, path_CFString, kCFURLPOSIXPathStyle, true); CFRelease(path_CFString); if (path_CFURL == NULL) { /* * XXX - does this always mean that that memory allocation failed? */ return (FALSE); } /* * XXX - this is a Launch Services result code, and we should probably * display a dialog box if it's not 0, describing what the error was. * Then again, we should probably do the same for the ShellExecute call, * unless that call itself happens to pop up a dialog box for all errors. */ status = LSOpenCFURLRef(path_CFURL, NULL); CFRelease(path_CFURL); return (status == 0); #elif defined(HAVE_XDG_OPEN) GError *error = NULL; gchar *argv[3]; gboolean retval; g_return_val_if_fail (path != NULL, FALSE); argv[0] = "xdg-open"; argv[1] = (char *)path; /* Grr - g_spawn_async() shouldn't modify this */ argv[2] = NULL; /* * XXX - use g_spawn_on_screen() so the file managaer window shows up on * the same screen? */ retval = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); if (! retval) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%sCould not execute xdg-open: %s\n\n\"%s\"", simple_dialog_primary_start(), simple_dialog_primary_end(), error->message); g_error_free (error); } return retval; #elif defined(MUST_LAUNCH_BROWSER_OURSELVES) GError *error = NULL; gchar *browser; gchar *argument; gchar *cmd; gchar **argv; gboolean retval; g_return_val_if_fail (path != NULL, FALSE); /* browser = gimp_gimprc_query ("web-browser");*/ browser = g_strdup(prefs.gui_webbrowser); if (browser == NULL || ! strlen (browser)) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "Web browser not specified.\n" "Please correct the web browser setting in the Preferences dialog."); g_free (browser); return FALSE; } /* conver the path to a URI */ argument = filename2uri (path); /* replace %s with URL */ if (strstr (browser, "%s")) cmd = strreplace (browser, "%s", argument); else cmd = g_strconcat (browser, " ", argument, NULL); g_free (argument); /* parse the cmd line */ if (! g_shell_parse_argv (cmd, NULL, &argv, &error)) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%sCould not parse web browser command: \"%s\"%s\n\n\"%s\"\n\n%s", simple_dialog_primary_start(), browser, simple_dialog_primary_end(), error->message, "Please correct the web browser setting in the Preferences dialog."); g_error_free (error); return FALSE; } /* * XXX - use g_spawn_on_screen() so the browser window shows up on * the same screen? */ retval = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); if (! retval) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%sCould not execute web browser: \"%s\"%s\n\n\"%s\"\n\n%s", simple_dialog_primary_start(), browser, simple_dialog_primary_end(), error->message, "Please correct the web browser setting in the Preferences dialog."); g_error_free (error); } g_free (browser); g_free (cmd); g_strfreev (argv); return retval; #endif }
gboolean browser_open_url (const gchar *url) { #if defined(G_OS_WIN32) return ((gint) ShellExecute (HWND_DESKTOP, _T("open"), utf_8to16(url), NULL, NULL, SW_SHOWNORMAL) > 32); #elif defined(HAVE_OS_X_FRAMEWORKS) CFStringRef url_CFString; CFURLRef url_CFURL; OSStatus status; /* * XXX - if URLs passed to "browser_open_url()" contain non-ASCII * characters, we'd have to choose an appropriate value from the * CFStringEncodings enum. */ url_CFString = CFStringCreateWithCString(NULL, url, kCFStringEncodingASCII); if (url_CFString == NULL) return (FALSE); url_CFURL = CFURLCreateWithString(NULL, url_CFString, NULL); CFRelease(url_CFString); if (url_CFURL == NULL) { /* * XXX - this could mean that the url_CFString wasn't a valid URL, * or that memory allocation failed. We can't determine which, * except perhaps by providing our own allocator and somehow * flagging allocation failures. */ return (FALSE); } /* * XXX - this is a Launch Services result code, and we should probably * display a dialog box if it's not 0, describing what the error was. * Then again, we should probably do the same for the ShellExecute call, * unless that call itself happens to pop up a dialog box for all errors. */ status = LSOpenCFURLRef(url_CFURL, NULL); CFRelease(url_CFURL); return (status == 0); #elif defined(HAVE_XDG_OPEN) GError *error = NULL; gchar *argv[3]; gboolean retval; g_return_val_if_fail (url != NULL, FALSE); argv[0] = "xdg-open"; argv[1] = (char *)url; /* Grr - g_spawn_async() shouldn't modify this */ argv[2] = NULL; /* * XXX - use g_spawn_on_screen() so the browser window shows up on * the same screen? */ retval = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); if (! retval) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%sCould not execute xdg-open: %s\n\n\"%s\"", simple_dialog_primary_start(), simple_dialog_primary_end(), error->message); g_error_free (error); } return retval; #elif defined(MUST_LAUNCH_BROWSER_OURSELVES) GError *error = NULL; gchar *browser; gchar *argument; gchar *cmd; gchar **argv; gboolean retval; g_return_val_if_fail (url != NULL, FALSE); /* browser = gimp_gimprc_query ("web-browser");*/ browser = g_strdup(prefs.gui_webbrowser); if (browser == NULL || ! strlen (browser)) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "Web browser not specified.\n" "Please correct the web browser setting in the Preferences dialog."); g_free (browser); return FALSE; } /* quote the url since it might contains special chars */ argument = g_shell_quote (url); /* replace %s with URL */ if (strstr (browser, "%s")) cmd = strreplace (browser, "%s", argument); else cmd = g_strconcat (browser, " ", argument, NULL); g_free (argument); /* parse the cmd line */ if (! g_shell_parse_argv (cmd, NULL, &argv, &error)) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%sCould not parse web browser command: \"%s\"%s\n\n\"%s\"\n\n%s", simple_dialog_primary_start(), browser, simple_dialog_primary_end(), error->message, "Please correct the web browser setting in the Preferences dialog."); g_error_free (error); return FALSE; } /* * XXX - use g_spawn_on_screen() so the browser window shows up on * the same screen? */ retval = g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); if (! retval) { simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%sCould not execute web browser: \"%s\"%s\n\n\"%s\"\n\n%s", simple_dialog_primary_start(), browser, simple_dialog_primary_end(), error->message, "Please correct the web browser setting in the Preferences dialog."); g_error_free (error); } g_free (browser); g_free (cmd); g_strfreev (argv); return retval; #endif }