From dc7cc4aba8bb5764cf50a0a0f37a1f3d173e9434 Mon Sep 17 00:00:00 2001 From: ulfl Date: Sat, 5 Feb 2005 15:35:25 +0000 Subject: [PATCH] rename kill_capture_child to capture_kill_child to have a common prefix split drag and drop support out of main.c into new file drag_and_drop.c, to reduce the size of main.c a bit. Hopefully this won't break unix builds because of missing #include's, I will keep an eye on the buildbot git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@13308 f5534014-38df-0310-8fa8-9805f1628bb7 --- capture.c | 2 +- capture.h | 2 +- capture_sync.c | 2 +- gtk/Makefile.common | 1 + gtk/drag_and_drop.c | 340 ++++++++++++++++++++++++++++++++++++++++++++ gtk/main.c | 292 +------------------------------------ gtk/main.h | 4 + 7 files changed, 349 insertions(+), 294 deletions(-) create mode 100644 gtk/drag_and_drop.c diff --git a/capture.c b/capture.c index 94bdb362e9..49a0f547e8 100644 --- a/capture.c +++ b/capture.c @@ -316,7 +316,7 @@ capture_stop(capture_options *capture_opts) } void -kill_capture_child(capture_options *capture_opts) +capture_kill_child(capture_options *capture_opts) { if (capture_opts->sync_mode) { sync_pipe_kill(capture_opts); diff --git a/capture.h b/capture.h index e52582aa80..6beeac44c3 100644 --- a/capture.h +++ b/capture.h @@ -102,7 +102,7 @@ extern int capture_start(capture_options *capture_opts, gboolean *stats_known, extern void capture_stop(capture_options *capture_opts); /** Terminate the capture child cleanly when exiting. */ -extern void kill_capture_child(capture_options *capture_opts); +extern void capture_kill_child(capture_options *capture_opts); /** Do the low-level work of a capture. */ extern int capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats); diff --git a/capture_sync.c b/capture_sync.c index 998acc4873..ae784106a7 100644 --- a/capture_sync.c +++ b/capture_sync.c @@ -642,7 +642,7 @@ sync_pipe_input_cb(gint source, gpointer user_data) case CF_READ_ABORTED: /* Kill the child capture process; the user wants to exit, and we shouldn't just leave it running. */ - kill_capture_child(capture_opts); + capture_kill_child(capture_opts); break; } diff --git a/gtk/Makefile.common b/gtk/Makefile.common index 686f41cb89..84a27e5f14 100644 --- a/gtk/Makefile.common +++ b/gtk/Makefile.common @@ -44,6 +44,7 @@ ETHEREAL_GTK_SRC = \ decode_as_dcerpc.c \ dfilter_expr_dlg.c \ dlg_utils.c \ + drag_and_drop.c \ ethereal-tap-register.c \ file_dlg.c \ filter_dlg.c \ diff --git a/gtk/drag_and_drop.c b/gtk/drag_and_drop.c new file mode 100644 index 0000000000..401f5803b7 --- /dev/null +++ b/gtk/drag_and_drop.c @@ -0,0 +1,340 @@ +/* dnd.c + * Drag and Drop + * + * $Id$ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_IO_H +#include /* open/close on win32 */ +#endif + + +#include + +#include "globals.h" + +#include "gtkglobals.h" +#include "util.h" +#include "file_dlg.h" +#include "../menu.h" +#include "compat_macros.h" +#include "file.h" +#include "simple_dialog.h" +#include + +#include +#include + + +enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL }; + +/* convert drag and drop URI to a local filename */ +static gchar * +dnd_uri2filename(gchar *cf_name) +{ + gchar *src, *dest; + gint ret; + guint i; + gchar esc[3]; + + + /* + * Remove URI header. + * On win32 (at least WinXP), this string looks like (UNC or local filename): + * file:////servername/sharename/dir1/dir2/capture-file.cap + * or + * file:///d:/dir1/dir2/capture-file.cap + * we have to remove the prefix to get a valid filename. + * + * On UNIX (at least KDE 3.0 Konqueror), this string looks like: + * file:/dir1/dir2/capture-file.cap + * we have to remove the file: to get a valid filename. + */ + if (strncmp("file:////", cf_name, 9) == 0) { + /* win32 UNC: now becoming: //servername/sharename/dir1/dir2/capture-file.cap */ + cf_name += 7; + } else if (strncmp("file:///", cf_name, 8) == 0) { + /* win32 local: now becoming: d:/dir1/dir2/capture-file.cap */ + cf_name += 8; + } else if (strncmp("file:", cf_name, 5) == 0) { + /* unix local: now becoming: /dir1/dir2/capture-file.cap */ + cf_name += 5; + } + + /* + * unescape the escaped URI characters (spaces, ...) + * + * we have to replace escaped chars to their equivalents, + * e.g. %20 (always a two digit hexstring) -> ' ' + * the percent character '%' is escaped be a double one "%%" + * + * we do this conversation "in place" as the result is always + * equal or smaller in size. + */ + src = cf_name; + dest = cf_name; + while (*src) { + if (*src == '%') { + src++; + if (*src == '%') { + /* this is an escaped '%' char (was: "%%") */ + *dest = *src; + src++; + dest++; + } else { + /* convert escaped hexnumber to unscaped character */ + esc[0] = src[0]; + esc[1] = src[1]; + esc[2] = '\0'; + ret = sscanf(esc, "%x", &i); + if (ret == 1) { + src+=2; + *dest = (gchar) i; + dest++; + } else { + /* somethings wrong, just jump over that char + * this will result in a wrong string, but we might get + * user feedback and can fix it later ;-) */ + src++; + } + } + } else { + *dest = *src; + src++; + dest++; + } + } + *dest = '\0'; + + return cf_name; +} + +static void +dnd_merge_files(int in_file_count, char **in_filenames) +{ + int out_fd; + gboolean merge_ok; + int err; + char tmpname[128+1]; + + + out_fd = create_tempfile(tmpname, sizeof tmpname, "ether"); + + /* merge the files in chonological order */ + merge_ok = cf_merge_files(tmpname, out_fd, in_file_count, in_filenames, + WTAP_FILE_PCAP, FALSE); + + if (!merge_ok) { + /* merge failed */ + close(out_fd); /* XXX - isn't it already closed? */ + return; + } + + cf_close(&cfile); + + /* Try to open the merged capture file. */ + if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) { + /* We couldn't open it; don't dismiss the open dialog box, + just leave it around so that the user can, after they + dismiss the alert box popped up for the open error, + try again. */ + return; + } + + switch (cf_read(&cfile)) { + + 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: + /* The user bailed out of re-reading the capture file; the + capture file has been closed - just free the capture file name + string and return (without changing the last containing + directory). */ + return; + } + + gtk_widget_grab_focus(packet_list); +} + +/* open/merge the dnd file */ +void +dnd_open_file_cmd(GtkSelectionData *selection_data) +{ + int err; + gchar *cf_name, *cf_name_freeme; + int in_files; + gpointer dialog; + GString *dialog_text; + int files_work; + char **in_filenames; + + + /* DND_TARGET_URL on Win32: + * The selection_data->data is a single string, containing one or more URI's, + * seperated 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. */ + + /* the data string is not zero terminated -> make a zero terminated "copy" of it */ + cf_name_freeme = g_malloc(selection_data->length + 1); + memcpy(cf_name_freeme, selection_data->data, selection_data->length); + cf_name_freeme[selection_data->length] = '\0'; + + /* count the number of input files */ + cf_name = cf_name_freeme; + for(in_files = 0; (cf_name = strstr(cf_name, "\r\n")) != NULL; ) { + cf_name += 2; + in_files++; + } + + in_filenames = g_malloc(sizeof(char*) * in_files); + + /* store the starts of the file entries in a gchar array */ + cf_name = cf_name_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_name_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]); + } + + switch(in_files) { + case(0): + /* shouldn't happen */ + break; + case(1): + /* open and read the capture file (this will close an existing file) */ + if (cf_open(&cfile, in_filenames[0], FALSE, &err) == CF_OK) { + cf_read(&cfile); + add_menu_recent_capture_file(in_filenames[0]); + } else { + /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */ + } + break; + default: + /* build and show the info dialog */ + dialog_text = g_string_sized_new(200); + g_string_append(dialog_text, PRIMARY_TEXT_START + "Merging the following files:" PRIMARY_TEXT_END "\n\n"); + 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."); + dialog = simple_dialog(ESD_TYPE_CONFIRMATION, + ESD_BTN_OK, + 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_name_freeme); +} + +/* ask the user to save current unsaved file, before opening the dnd file */ +static void +dnd_save_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_) +{ + switch(btn) { + case(ESD_BTN_SAVE): + /* save file first */ + file_save_as_cmd(after_save_open_dnd_file, data); + break; + case(ESD_BTN_DONT_SAVE): + cf_close(&cfile); + dnd_open_file_cmd(data); + break; + case(ESD_BTN_CANCEL): + break; + default: + g_assert_not_reached(); + } +} + + +/* we have received some drag and drop data */ +/* (as we only registered to "text/uri-list", we will only get a file list here) */ +static void +dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_, +GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_) +{ + gpointer dialog; + + if (info == DND_TARGET_URL) { + /* ask the user to save it's current capture file first */ + if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) { + /* user didn't saved his current file, ask him */ + dialog = simple_dialog(ESD_TYPE_CONFIRMATION, + ESD_BTNS_SAVE_DONTSAVE_CANCEL, + PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n" + "If you open a new capture file without saving, your current capture data will be discarded."); + simple_dialog_set_cb(dialog, dnd_save_file_answered_cb, selection_data); + } else { + /* unchanged file */ + dnd_open_file_cmd(selection_data); + } + } +} + +/* init the drag and drop functionality */ +void +dnd_init(GtkWidget *w) +{ + /* we are only interested in the URI list containing filenames */ + static GtkTargetEntry target_entry[] = { + /*{"STRING", 0, DND_TARGET_STRING},*/ + /*{"text/plain", 0, DND_TARGET_STRING},*/ + {"text/uri-list", 0, DND_TARGET_URL} + }; + + /* set this window as a dnd destination */ + gtk_drag_dest_set( + w, GTK_DEST_DEFAULT_ALL, target_entry, + sizeof(target_entry) / sizeof(GtkTargetEntry), + (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) ); + + /* get notified, if some dnd coming in */ + gtk_signal_connect(GTK_OBJECT(w), "drag_data_received", + GTK_SIGNAL_FUNC(dnd_data_received), NULL); +} + + diff --git a/gtk/main.c b/gtk/main.c index a236daf7d1..f66f5854f3 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -881,7 +881,7 @@ main_do_quit(void) #ifdef HAVE_LIBPCAP /* Nuke any child capture in progress. */ - kill_capture_child(capture_opts); + capture_kill_child(capture_opts); #endif /* Are we in the middle of reading a capture? */ @@ -1326,296 +1326,6 @@ register_ethereal_tap(char *cmd, void (*func)(char *arg)) } -enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL }; - -/* convert drag and drop URI to a local filename */ -static gchar * -dnd_uri2filename(gchar *cf_name) -{ - gchar *src, *dest; - gint ret; - guint i; - gchar esc[3]; - - - /* - * Remove URI header. - * On win32 (at least WinXP), this string looks like (UNC or local filename): - * file:////servername/sharename/dir1/dir2/capture-file.cap - * or - * file:///d:/dir1/dir2/capture-file.cap - * we have to remove the prefix to get a valid filename. - * - * On UNIX (at least KDE 3.0 Konqueror), this string looks like: - * file:/dir1/dir2/capture-file.cap - * we have to remove the file: to get a valid filename. - */ - if (strncmp("file:////", cf_name, 9) == 0) { - /* win32 UNC: now becoming: //servername/sharename/dir1/dir2/capture-file.cap */ - cf_name += 7; - } else if (strncmp("file:///", cf_name, 8) == 0) { - /* win32 local: now becoming: d:/dir1/dir2/capture-file.cap */ - cf_name += 8; - } else if (strncmp("file:", cf_name, 5) == 0) { - /* unix local: now becoming: /dir1/dir2/capture-file.cap */ - cf_name += 5; - } - - /* - * unescape the escaped URI characters (spaces, ...) - * - * we have to replace escaped chars to their equivalents, - * e.g. %20 (always a two digit hexstring) -> ' ' - * the percent character '%' is escaped be a double one "%%" - * - * we do this conversation "in place" as the result is always - * equal or smaller in size. - */ - src = cf_name; - dest = cf_name; - while (*src) { - if (*src == '%') { - src++; - if (*src == '%') { - /* this is an escaped '%' char (was: "%%") */ - *dest = *src; - src++; - dest++; - } else { - /* convert escaped hexnumber to unscaped character */ - esc[0] = src[0]; - esc[1] = src[1]; - esc[2] = '\0'; - ret = sscanf(esc, "%x", &i); - if (ret == 1) { - src+=2; - *dest = (gchar) i; - dest++; - } else { - /* somethings wrong, just jump over that char - * this will result in a wrong string, but we might get - * user feedback and can fix it later ;-) */ - src++; - } - } - } else { - *dest = *src; - src++; - dest++; - } - } - *dest = '\0'; - - return cf_name; -} - -static void -dnd_merge_files(int in_file_count, char **in_filenames) -{ - int out_fd; - gboolean merge_ok; - int err; - char tmpname[128+1]; - - - out_fd = create_tempfile(tmpname, sizeof tmpname, "ether"); - - /* merge the files in chonological order */ - merge_ok = cf_merge_files(tmpname, out_fd, in_file_count, in_filenames, - WTAP_FILE_PCAP, FALSE); - - if (!merge_ok) { - /* merge failed */ - close(out_fd); /* XXX - isn't it already closed? */ - return; - } - - cf_close(&cfile); - - /* Try to open the merged capture file. */ - if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) { - /* We couldn't open it; don't dismiss the open dialog box, - just leave it around so that the user can, after they - dismiss the alert box popped up for the open error, - try again. */ - return; - } - - switch (cf_read(&cfile)) { - - 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: - /* The user bailed out of re-reading the capture file; the - capture file has been closed - just free the capture file name - string and return (without changing the last containing - directory). */ - return; - } - - gtk_widget_grab_focus(packet_list); -} - -/* open/merge the dnd file */ -void -dnd_open_file_cmd(GtkSelectionData *selection_data) -{ - int err; - gchar *cf_name, *cf_name_freeme; - int in_files; - gpointer dialog; - GString *dialog_text; - int files_work; - char **in_filenames; - - - /* DND_TARGET_URL on Win32: - * The selection_data->data is a single string, containing one or more URI's, - * seperated 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. */ - - /* the data string is not zero terminated -> make a zero terminated "copy" of it */ - cf_name_freeme = g_malloc(selection_data->length + 1); - memcpy(cf_name_freeme, selection_data->data, selection_data->length); - cf_name_freeme[selection_data->length] = '\0'; - - /* count the number of input files */ - cf_name = cf_name_freeme; - for(in_files = 0; (cf_name = strstr(cf_name, "\r\n")) != NULL; ) { - cf_name += 2; - in_files++; - } - - in_filenames = g_malloc(sizeof(char*) * in_files); - - /* store the starts of the file entries in a gchar array */ - cf_name = cf_name_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_name_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]); - } - - switch(in_files) { - case(0): - /* shouldn't happen */ - break; - case(1): - /* open and read the capture file (this will close an existing file) */ - if (cf_open(&cfile, in_filenames[0], FALSE, &err) == CF_OK) { - cf_read(&cfile); - add_menu_recent_capture_file(in_filenames[0]); - } else { - /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */ - } - break; - default: - /* build and show the info dialog */ - dialog_text = g_string_sized_new(200); - g_string_append(dialog_text, PRIMARY_TEXT_START - "Merging the following files:" PRIMARY_TEXT_END "\n\n"); - 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."); - dialog = simple_dialog(ESD_TYPE_CONFIRMATION, - ESD_BTN_OK, - 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_name_freeme); -} - -/* ask the user to save current unsaved file, before opening the dnd file */ -static void -dnd_save_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_) -{ - switch(btn) { - case(ESD_BTN_SAVE): - /* save file first */ - file_save_as_cmd(after_save_open_dnd_file, data); - break; - case(ESD_BTN_DONT_SAVE): - cf_close(&cfile); - dnd_open_file_cmd(data); - break; - case(ESD_BTN_CANCEL): - break; - default: - g_assert_not_reached(); - } -} - - -/* we have received some drag and drop data */ -/* (as we only registered to "text/uri-list", we will only get a file list here) */ -static void -dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_, -GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_) -{ - gpointer dialog; - - if (info == DND_TARGET_URL) { - /* ask the user to save it's current capture file first */ - if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) { - /* user didn't saved his current file, ask him */ - dialog = simple_dialog(ESD_TYPE_CONFIRMATION, - ESD_BTNS_SAVE_DONTSAVE_CANCEL, - PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n" - "If you open a new capture file without saving, your current capture data will be discarded."); - simple_dialog_set_cb(dialog, dnd_save_file_answered_cb, selection_data); - } else { - /* unchanged file */ - dnd_open_file_cmd(selection_data); - } - } -} - -/* init the drag and drop functionality */ -static void -dnd_init(GtkWidget *w) -{ - /* we are only interested in the URI list containing filenames */ - static GtkTargetEntry target_entry[] = { - /*{"STRING", 0, DND_TARGET_STRING},*/ - /*{"text/plain", 0, DND_TARGET_STRING},*/ - {"text/uri-list", 0, DND_TARGET_URL} - }; - - /* set this window as a dnd destination */ - gtk_drag_dest_set( - w, GTK_DEST_DEFAULT_ALL, target_entry, - sizeof(target_entry) / sizeof(GtkTargetEntry), - (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) ); - - /* get notified, if some dnd coming in */ - gtk_signal_connect(GTK_OBJECT(w), "drag_data_received", - GTK_SIGNAL_FUNC(dnd_data_received), NULL); -} - - /* And now our feature presentation... [ fade to music ] */ int main(int argc, char *argv[]) diff --git a/gtk/main.h b/gtk/main.h index cad3fe317f..50d85c7710 100644 --- a/gtk/main.h +++ b/gtk/main.h @@ -262,6 +262,10 @@ extern void main_widgets_show_or_hide(void); extern gboolean main_filter_packets(capture_file *cf, const gchar *dftext, gboolean force); +/** Init the drag-n-drop functionality. + */ +extern void dnd_init(void); + /** Open a new file coming from drag and drop. * @param selection_data the selection data reported from GTK */