2 * An API for Wireshark plugins
4 * This enables wireshark dissectors, especially those implemented by plugins
5 * to register menubar entries, which then will call a pre-defined callback
6 * function for the dissector or plugin.
8 * Also it implements additional methods, which allow plugins to interoperate
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * SPDX-License-Identifier: GPL-2.0-or-later
21 #include <epan/epan.h>
22 #include <epan/proto.h>
23 #include <wsutil/ws_assert.h>
25 #include "plugin_if.h"
27 static GList
* menubar_entries
;
28 static GList
* menubar_menunames
;
30 static GHashTable
* plugin_if_callback_functions
;
33 plugin_if_init_hashtable(void)
35 if ( plugin_if_callback_functions
== 0 )
36 plugin_if_callback_functions
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
39 static void plugin_if_call_gui_cb(plugin_if_callback_t actionType
, GHashTable
* dataSet
)
41 plugin_if_gui_cb action
;
43 plugin_if_init_hashtable();
45 if ( g_hash_table_lookup_extended(plugin_if_callback_functions
, GINT_TO_POINTER(actionType
), NULL
, (void **)&action
) )
53 extern GList
* ext_menubar_get_entries(void)
55 return menubar_entries
;
58 extern ext_menu_t
* ext_menubar_register_menu(int proto_id
, const char * menulabel
,
61 ext_menubar_t
* entry
= NULL
;
64 /* A name for the entry must be provided */
65 ws_assert(menulabel
!= NULL
&& strlen ( menulabel
) > 0 );
67 /* A protocol must exist for the given id */
68 ws_assert(find_protocol_by_id(proto_id
) != NULL
);
70 /* Create unique name, which is used by GTK to provide the menu */
71 name
= g_strconcat(proto_get_protocol_filter_name(proto_id
), "Menu", NULL
);
73 /* For now, a protocol may only register one main menu */
74 ws_assert(g_list_find(menubar_menunames
, name
) == NULL
);
76 entry
= g_new0(ext_menubar_t
, 1);
77 entry
->type
= EXT_MENUBAR_MENU
;
78 entry
->proto
= proto_id
;
79 entry
->is_plugin
= is_plugin
;
81 entry
->parent_menu
= 0;
83 /* Create a name for this submenu */
85 entry
->label
= g_strdup(menulabel
);
86 entry
->tooltip
= g_strdup(menulabel
);
88 entry
->submenu_cnt
= 0;
91 menubar_entries
= g_list_append(menubar_entries
, entry
);
92 menubar_menunames
= g_list_append(menubar_menunames
, name
);
97 extern ext_menu_t
* ext_menubar_set_parentmenu(ext_menu_t
* menu
, const char * parentmenu
)
99 ws_assert(menu
!= NULL
&& menu
->parent
== NULL
);
101 ws_assert(parentmenu
!= 0);
103 menu
->parent_menu
= g_strdup(parentmenu
);
108 extern ext_menu_t
* ext_menubar_add_submenu(ext_menu_t
* parent
, const char *menulabel
)
110 ext_menubar_t
* entry
= NULL
;
112 /* A name for the entry must be provided */
113 ws_assert(menulabel
!= NULL
&& strlen ( menulabel
) > 0 );
115 /* Parent must be a valid parent */
116 ws_assert(parent
!= NULL
&& parent
->type
== EXT_MENUBAR_MENU
);
118 parent
->submenu_cnt
++;
120 /* Create submenu entry */
121 entry
= g_new0(ext_menubar_t
, 1);
122 entry
->type
= EXT_MENUBAR_MENU
;
123 entry
->parent
= parent
;
124 /* Just a convenience */
125 entry
->proto
= parent
->proto
;
126 entry
->is_plugin
= parent
->is_plugin
;
127 /* Create unique name, which is used by GTK to provide the menu */
128 entry
->name
= ws_strdup_printf("%sS%02d", parent
->name
, parent
->submenu_cnt
);
129 entry
->label
= g_strdup(menulabel
);
130 entry
->tooltip
= g_strdup(menulabel
);
132 parent
->children
= g_list_append(parent
->children
, entry
);
137 static void ext_menubar_add_generic_entry (
138 ext_menubar_entry_t type
, ext_menu_t
* parent
, const char * label
,
139 const char * tooltip
, ext_menubar_action_cb callback
, void *user_data
)
141 ext_menubar_t
* entry
= NULL
;
143 /* A valid parent must exist */
144 ws_assert(parent
!= NULL
&& parent
->type
== EXT_MENUBAR_MENU
);
145 /* A label for the entry must be provided */
146 ws_assert(label
!= NULL
&& strlen ( label
) > 0 );
150 /* Create menu entry */
151 entry
= g_new0(ext_menubar_t
, 1);
153 /* Create unique name, which is used by GTK to provide the menu */
154 entry
->name
= ws_strdup_printf("%sI%02d", parent
->name
, parent
->item_cnt
);
155 entry
->label
= g_strdup(label
);
157 if ( tooltip
!= NULL
&& strlen(tooltip
) > 0 )
158 entry
->tooltip
= g_strdup(tooltip
);
160 entry
->callback
= callback
;
161 entry
->user_data
= user_data
;
163 parent
->children
= g_list_append(parent
->children
, entry
);
166 extern void ext_menubar_add_entry(ext_menu_t
* parent
, const char *label
,
167 const char *tooltip
, ext_menubar_action_cb callback
, void *user_data
)
169 /* A callback must be provided */
170 ws_assert(callback
!= NULL
);
172 ext_menubar_add_generic_entry ( EXT_MENUBAR_ITEM
, parent
, label
, tooltip
, callback
, user_data
);
175 extern void ext_menubar_add_website(ext_menu_t
* parent
, const char *label
,
176 const char *tooltip
, const char *url
)
178 /* An url for the entry must be provided */
179 ws_assert(url
!= NULL
&& strlen ( url
) > 0 );
181 ext_menubar_add_generic_entry ( EXT_MENUBAR_URL
, parent
, label
, tooltip
, NULL
, (void *) g_strdup(url
) );
184 extern void ext_menubar_add_separator(ext_menu_t
*parent
)
186 ext_menubar_add_generic_entry ( EXT_MENUBAR_SEPARATOR
, parent
, "-", NULL
, NULL
, NULL
);
189 /* Implementation of external toolbar handlers */
191 static GList
* toolbar_entries
;
193 extern GList
* ext_toolbar_get_entries(void)
195 return toolbar_entries
;
198 ext_toolbar_t
* ext_toolbar_register_toolbar(const char * toolbarlabel
)
200 ext_toolbar_t
* entry
= NULL
;
202 /* A name for the entry must be provided */
203 ws_assert(toolbarlabel
!= NULL
&& strlen ( toolbarlabel
) > 0 );
205 entry
= g_new0(ext_toolbar_t
, 1);
206 entry
->type
= EXT_TOOLBAR_BAR
;
208 /* Create a name for this toolbar */
209 entry
->name
= g_strdup(toolbarlabel
);
210 entry
->tooltip
= g_strdup(toolbarlabel
);
212 entry
->submenu_cnt
= 0;
215 toolbar_entries
= g_list_append(toolbar_entries
, entry
);
221 ext_toolbar_compare(const void * a
, const void * b
)
226 const ext_toolbar_t
* ta
= (const ext_toolbar_t
*)a
;
227 const ext_toolbar_t
* tb
= (const ext_toolbar_t
*)b
;
229 return strcmp(ta
->name
, tb
->name
);
232 void ext_toolbar_unregister_toolbar_by_name(const char * toolbar_name
)
236 if ( ! toolbar_name
)
239 walker
= toolbar_entries
;
240 while ( walker
&& walker
->data
)
242 ext_toolbar_t
* entry
= (ext_toolbar_t
*)walker
->data
;
243 if ( g_strcmp0(entry
->name
, toolbar_name
) == 0)
245 ext_toolbar_unregister_toolbar(entry
);
249 walker
= g_list_next(walker
);
253 void ext_toolbar_unregister_toolbar(ext_toolbar_t
* toolbar
)
258 GList
* entry
= g_list_find_custom(toolbar_entries
, toolbar
, (GCompareFunc
) ext_toolbar_compare
);
259 if ( entry
&& entry
->data
)
261 ext_toolbar_t
* et
= (ext_toolbar_t
*)entry
->data
;
262 toolbar_entries
= g_list_remove(toolbar_entries
, et
);
264 if ( ! g_list_find_custom(toolbar_entries
, toolbar
, (GCompareFunc
) ext_toolbar_compare
) )
266 GHashTable
* dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
267 g_hash_table_insert( dataSet
, g_strdup("toolbar_name"), g_strdup(et
->name
) );
268 plugin_if_call_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR
, dataSet
);
272 g_free(et
->defvalue
);
281 ext_toolbar_insert_sort(const void *a
, const void *b
)
283 const ext_toolbar_t
* ca
= (const ext_toolbar_t
*)a
;
284 const ext_toolbar_t
* cb
= (const ext_toolbar_t
*)b
;
286 if ( ca
== 0 || cb
== 0 )
289 /* Sort buttons after rest of objects */
290 if ( ca
->item_type
== EXT_TOOLBAR_BUTTON
&& cb
->item_type
!= EXT_TOOLBAR_BUTTON
)
292 else if ( ca
->item_type
!= EXT_TOOLBAR_BUTTON
&& cb
->item_type
== EXT_TOOLBAR_BUTTON
)
296 if ( ca
->item_cnt
> cb
->item_cnt
)
298 else if ( ca
->item_cnt
< cb
->item_cnt
)
306 ext_toolbar_add_entry( ext_toolbar_t
* parent
, ext_toolbar_item_t type
, const char *label
,
307 const char *defvalue
, const char *tooltip
, bool capture_only
, GList
* value_list
,
308 bool is_required
, const char * regex
, ext_toolbar_action_cb callback
, void *user_data
)
310 ext_toolbar_t
* entry
= NULL
;
312 /* A valid parent must exist */
313 ws_assert(parent
!= NULL
&& parent
->type
== EXT_TOOLBAR_BAR
);
314 /* A label for the entry must be provided */
315 ws_assert(label
!= NULL
&& strlen ( label
) > 0 );
316 /* A callback must be provided */
317 ws_assert(callback
!= NULL
);
321 /* Create menu entry */
322 entry
= g_new0(ext_toolbar_t
, 1);
323 entry
->type
= EXT_TOOLBAR_ITEM
;
324 entry
->item_type
= type
;
325 entry
->item_cnt
= g_list_length(parent
->children
) + 1;
327 entry
->name
= g_strdup(label
);
329 if ( tooltip
!= NULL
&& strlen(tooltip
) > 0 )
330 entry
->tooltip
= g_strdup(tooltip
);
332 if ( defvalue
!= NULL
&& strlen(defvalue
) > 0 )
333 entry
->defvalue
= g_strdup(defvalue
);
335 if ( value_list
!= NULL
&& g_list_length(value_list
) > 0 )
336 entry
->values
= g_list_copy(value_list
);
338 entry
->regex
= g_strdup(regex
);
340 entry
->is_required
= is_required
;
341 entry
->capture_only
= capture_only
;
342 entry
->callback
= callback
;
343 entry
->user_data
= user_data
;
345 parent
->children
= g_list_insert_sorted(parent
->children
, entry
, ext_toolbar_insert_sort
);
351 ext_toolbar_search_label(const void *tb
, const void *lbl
)
356 const ext_toolbar_t
* toolbar
= (const ext_toolbar_t
*) tb
;
357 if ( toolbar
->type
!= EXT_TOOLBAR_ITEM
)
360 const char * label
= (const char * )lbl
;
362 return g_strcmp0(toolbar
->name
, label
);
365 ext_toolbar_t
* ext_toolbar_entry_by_label(const ext_toolbar_t
* toolbar
, const char * label
)
367 ext_toolbar_t
* result
= 0;
368 GList
* entry
= g_list_find_custom(toolbar
->children
, label
, ext_toolbar_search_label
);
370 result
= (ext_toolbar_t
*)entry
->data
;
374 GList
* ext_toolbar_add_val(GList
* entries
, char * value
, char * display
, bool is_default
)
376 ext_toolbar_value_t
* newval
= g_new0(ext_toolbar_value_t
, 1);
377 newval
->value
= g_strdup(value
);
378 newval
->display
= g_strdup(display
);
379 newval
->is_default
= is_default
;
381 return g_list_append(entries
, newval
);
384 typedef struct _ext_toolbar_update_entry_t
386 ext_toolbar_action_cb callback
;
388 } ext_toolbar_update_entry_t
;
390 typedef struct _ext_toolbar_update_list_t
392 ext_toolbar_t
* item
;
394 } ext_toolbar_update_list_t
;
397 ext_toolbar_find_item(const void *a
, const void *b
)
399 if ( a
== 0 || b
== 0 )
402 const ext_toolbar_update_list_t
* item
= (const ext_toolbar_update_list_t
*)a
;
403 const ext_toolbar_t
* entry
= (const ext_toolbar_t
*)b
;
405 if ( item
->item
&& g_strcmp0 ( item
->item
->name
, entry
->name
) == 0 )
411 static GList
* toolbar_updates
;
413 void ext_toolbar_register_update_cb(ext_toolbar_t
* entry
, ext_toolbar_action_cb callback
, void *item_data
)
415 if ( entry
== 0 || item_data
== 0 || callback
== 0 )
418 ext_toolbar_update_list_t
* update
= NULL
;
419 GList
* update_list
= g_list_find_custom(toolbar_updates
, entry
, ext_toolbar_find_item
);
422 update
= g_new0(ext_toolbar_update_list_t
, 1);
423 update
->item
= entry
;
424 toolbar_updates
= g_list_append(toolbar_updates
, update
);
428 update
= (ext_toolbar_update_list_t
*)update_list
->data
;
431 ext_toolbar_update_entry_t
* update_entry
= g_new0(ext_toolbar_update_entry_t
, 1);
432 update_entry
->callback
= callback
;
433 update_entry
->item_data
= item_data
;
434 update
->entries
= g_list_append(update
->entries
, update_entry
);
438 ext_toolbar_update_entry(ext_toolbar_update_type_t update_type
, ext_toolbar_t
* entry
, void *data
, void *idx
, bool silent
)
440 GList
* update
= g_list_find_custom(toolbar_updates
, entry
, ext_toolbar_find_item
);
441 GList
* walker
= NULL
;
443 if ( ! update
|| ! update
->data
)
446 ext_toolbar_update_t
* update_data
= g_new0(ext_toolbar_update_t
, 1);
447 update_data
->user_data
= data
;
448 update_data
->data_index
= idx
;
449 update_data
->silent
= silent
;
450 update_data
->type
= update_type
;
452 walker
= ((ext_toolbar_update_list_t
*)(update
->data
))->entries
;
454 while ( walker
&& walker
->data
)
456 ext_toolbar_update_entry_t
* update_entry
= (ext_toolbar_update_entry_t
*)walker
->data
;
458 if ( update_entry
->callback
&& update_entry
->item_data
)
459 update_entry
->callback(entry
, update_entry
->item_data
, update_data
);
460 walker
= g_list_next(walker
);
466 void ext_toolbar_update_value(ext_toolbar_t
* entry
, void *data
, bool silent
)
468 ext_toolbar_update_entry( EXT_TOOLBAR_UPDATE_VALUE
, entry
, data
, NULL
, silent
);
471 void ext_toolbar_update_data(ext_toolbar_t
* entry
, void *data
, bool silent
)
473 if ( entry
->item_type
== EXT_TOOLBAR_SELECTOR
)
474 ext_toolbar_update_entry( EXT_TOOLBAR_UPDATE_DATA
, entry
, data
, NULL
, silent
);
477 void ext_toolbar_update_data_by_index(ext_toolbar_t
* entry
, void *data
, void *idx
, bool silent
)
479 if ( entry
->item_type
== EXT_TOOLBAR_SELECTOR
)
480 ext_toolbar_update_entry( EXT_TOOLBAR_UPDATE_DATABYINDEX
, entry
, data
, idx
, silent
);
483 void ext_toolbar_update_data_add_entry(ext_toolbar_t
* entry
, void *data
, void *idx
, bool silent
)
485 if ( entry
->item_type
== EXT_TOOLBAR_SELECTOR
)
486 ext_toolbar_update_entry( EXT_TOOLBAR_UPDATE_DATA_ADD
, entry
, data
, idx
, silent
);
489 void ext_toolbar_update_data_remove_entry(ext_toolbar_t
* entry
, void *data
, void *idx
, bool silent
)
491 if ( entry
->item_type
== EXT_TOOLBAR_SELECTOR
)
492 ext_toolbar_update_entry( EXT_TOOLBAR_UPDATE_DATA_REMOVE
, entry
, data
, idx
, silent
);
495 void ext_toolbar_update_data_set_active(ext_toolbar_t
* entry
, bool status
)
497 ext_toolbar_update_entry(EXT_TOOLBAR_SET_ACTIVE
, entry
, GINT_TO_POINTER(status
? 1 : 0), 0, true );
500 /* Implementation of GUI callback methods follows.
501 * This is a necessity, as using modern UI systems, gui interfaces often operate
502 * in different threads then the calling application. Even more so, if the calling
503 * application is implemented using a separate plugin. Therefore the external menubars
504 * cannot call gui functionality directly, the gui has to perform the function within
507 extern void plugin_if_apply_filter(const char * filter_string
, bool force
)
509 plugin_if_callback_t actionType
;
510 GHashTable
* dataSet
= NULL
;
512 actionType
= ( force
== true ) ? PLUGIN_IF_FILTER_ACTION_APPLY
: PLUGIN_IF_FILTER_ACTION_PREPARE
;
513 dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
515 g_hash_table_insert( dataSet
, g_strdup("action_type"), (void *) &actionType
);
516 g_hash_table_insert( dataSet
, g_strdup("filter_string"), g_strdup(filter_string
) );
517 g_hash_table_insert( dataSet
, g_strdup("force"), (void *) &force
);
519 plugin_if_call_gui_cb(actionType
, dataSet
);
522 extern void plugin_if_goto_frame(uint32_t framenr
)
524 GHashTable
* dataSet
= NULL
;
526 dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
528 g_hash_table_insert( dataSet
, g_strdup("frame_nr"), GUINT_TO_POINTER(framenr
) );
530 plugin_if_call_gui_cb(PLUGIN_IF_GOTO_FRAME
, dataSet
);
533 extern void plugin_if_save_preference(const char * pref_module
, const char * pref_key
, const char * pref_value
)
535 GHashTable
* dataSet
= NULL
;
537 dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
539 g_hash_table_insert( dataSet
, g_strdup("pref_module"), g_strdup(pref_module
) );
540 g_hash_table_insert( dataSet
, g_strdup("pref_key"), g_strdup(pref_key
) );
541 g_hash_table_insert( dataSet
, g_strdup("pref_value"), g_strdup(pref_value
) );
543 plugin_if_call_gui_cb(PLUGIN_IF_PREFERENCE_SAVE
, dataSet
);
546 extern void plugin_if_get_ws_info(ws_info_t
**ws_info_ptr
)
548 static ws_info_t ws_info
= { false, FILE_CLOSED
, NULL
, 0, 0, false };
551 GHashTable
* dataSet
;
552 char * pluginKey
= g_strdup("ws_info");
554 dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
556 g_hash_table_insert(dataSet
, pluginKey
, &ws_info
);
558 plugin_if_call_gui_cb(PLUGIN_IF_GET_WS_INFO
, dataSet
);
560 g_hash_table_destroy(dataSet
);
565 /* Initialise the ws_info structure */
567 ws_info
.ws_info_supported
= false;
568 ws_info
.cf_count
= 0;
569 ws_info
.cf_filename
= NULL
;
570 ws_info
.cf_framenr
= 0;
571 ws_info
.frame_passed_dfilter
= false;
572 ws_info
.cf_state
= FILE_CLOSED
;
574 #endif /* HAVE_LIBPCAP */
576 *ws_info_ptr
= &ws_info
;
579 extern void* plugin_if_get_frame_data(plugin_if_frame_data_cb extract_cb
, void* user_data
) {
580 GHashTable
* dataSet
= NULL
;
581 void* ret_value
= NULL
;
583 dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
585 g_hash_table_insert(dataSet
, g_strdup("extract_cb"), extract_cb
);
586 g_hash_table_insert(dataSet
, g_strdup("user_data"), user_data
);
587 g_hash_table_insert(dataSet
, g_strdup("ret_value_ptr"), &ret_value
);
589 plugin_if_call_gui_cb(PLUGIN_IF_GET_FRAME_DATA
, dataSet
);
591 g_hash_table_destroy(dataSet
);
596 extern void* plugin_if_get_capture_file(plugin_if_capture_file_cb extract_cb
, void* user_data
) {
597 GHashTable
* dataSet
= NULL
;
598 void* ret_value
= NULL
;
600 dataSet
= g_hash_table_new(g_str_hash
, g_str_equal
);
602 g_hash_table_insert(dataSet
, g_strdup("extract_cb"), extract_cb
);
603 g_hash_table_insert(dataSet
, g_strdup("user_data"), user_data
);
604 g_hash_table_insert(dataSet
, g_strdup("ret_value_ptr"), &ret_value
);
606 plugin_if_call_gui_cb(PLUGIN_IF_GET_CAPTURE_FILE
, dataSet
);
608 g_hash_table_destroy(dataSet
);
613 extern void plugin_if_register_gui_cb(plugin_if_callback_t actionType
, plugin_if_gui_cb callback
)
615 plugin_if_init_hashtable();
617 if ( ! g_hash_table_lookup_extended(plugin_if_callback_functions
, GINT_TO_POINTER(actionType
), NULL
, NULL
) )
618 g_hash_table_insert(plugin_if_callback_functions
, GINT_TO_POINTER(actionType
), (void *)callback
);
627 * indent-tabs-mode: nil
630 * ex: set shiftwidth=4 tabstop=8 expandtab:
631 * :indentSize=4:tabSize=8:noTabs=true: