4 * (c) 2006, Luis E. Garcia Ontanon <luis@ontanon.org>
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 #define WS_LOG_DOMAIN LOG_DOMAIN_WSLUA
16 #include <epan/wmem_scopes.h>
20 /* WSLUA_MODULE Gui GUI Support */
22 static const funnel_ops_t
* ops
;
24 struct _lua_menu_data
{
29 static int menu_cb_error_handler(lua_State
* L
) {
30 const char* error
= lua_tostring(L
,1);
31 report_failure("Lua: Error during execution of Menu callback:\n %s",error
);
35 WSLUA_FUNCTION
wslua_gui_enabled(lua_State
* L
) { /* Checks if we're running inside a GUI (i.e. Wireshark) or not. */
36 lua_pushboolean(L
,GPOINTER_TO_INT(ops
&& ops
->add_button
));
37 WSLUA_RETURN(1); /* Boolean `true` if a GUI is available, `false` if it isn't. */
40 static void lua_menu_callback(void *data
) {
41 struct _lua_menu_data
* md
= (struct _lua_menu_data
*)data
;
45 lua_pushcfunction(L
,menu_cb_error_handler
);
46 lua_rawgeti(L
, LUA_REGISTRYINDEX
, md
->cb_ref
);
48 switch ( lua_pcall(L
,0,0,1) ) {
52 ws_warning("Runtime error while calling menu callback");
55 ws_warning("Memory alloc error while calling menu callback");
58 ws_warning("Error while running the error handler function for menu callback");
61 ws_assert_not_reached();
68 WSLUA_FUNCTION
wslua_register_menu(lua_State
* L
) { /* Register a menu item in one of the main menus. Requires a GUI. */
69 #define WSLUA_ARG_register_menu_NAME 1 /* The name of the menu item. Use slashes to separate submenus. (e.g. menu:Lua Scripts[My Fancy Statistics]). (string) */
70 #define WSLUA_ARG_register_menu_ACTION 2 /* The function to be called when the menu item is invoked. The function must take no arguments and return nothing. */
71 #define WSLUA_OPTARG_register_menu_GROUP 3 /*
72 Where to place the item in the menu hierarchy.
73 If omitted, defaults to MENU_STAT_GENERIC.
74 Valid packet (Wireshark) items are:
75 * MENU_PACKET_ANALYZE_UNSORTED: menu:Analyze[]
76 * MENU_PACKET_STAT_UNSORTED: menu:Statistics[]
77 * MENU_STAT_GENERIC: menu:Statistics[], first section
78 * MENU_STAT_RESPONSE_TIME: menu:Statistics[Service Response Time]
79 * MENU_STAT_RSERPOOL: menu:Statistics[Reliable Server Pooling (RSerPool)]
80 * MENU_TELEPHONY_UNSORTED: menu:Telephony[]
81 * MENU_TELEPHONY_ANSI: menu:Telephony[ANSI]
82 * MENU_TELEPHONY_GSM: menu:Telephony[GSM]
83 * MENU_TELEPHONY_3GPP_UU: menu:Telephony[3GPP Uu]
84 * MENU_TELEPHONY_MTP3: menu:Telephony[MTP3]
85 * MENU_TELEPHONY_SCTP: menu:Telephony[SCTP]
86 * MENU_TOOLS_UNSORTED: menu:Tools[]
88 Valid log (Stratoshark) items are:
89 * MENU_LOG_ANALYZE_UNSORTED: menu:Analyze[]
90 * MENU_LOG_STAT_UNSORTED: menu:Statistics[]
92 The following are deprecated and shouldn't be used in new code:
93 * MENU_ANALYZE_CONVERSATION_FILTER, menu:Analyze[Conversation Filter] registration is not yet supported in Lua
94 * MENU_STAT_CONVERSATION_LIST, menu:Statistics[Conversations] registration is not yet supported in Lua
95 * MENU_STAT_ENDPOINT_LIST, menu:Statistics[Endpoints] registration is not yet supported in Lua
96 * MENU_ANALYZE_UNSORTED, superseded by MENU_PACKET_ANALYZE_UNSORTED
97 * MENU_ANALYZE_CONVERSATION, superseded by MENU_ANALYZE_CONVERSATION_FILTER
98 * MENU_STAT_CONVERSATION, superseded by MENU_STAT_CONVERSATION_LIST
99 * MENU_STAT_ENDPOINT, superseded by MENU_STAT_ENDPOINT_LIST
100 * MENU_STAT_RESPONSE, superseded by MENU_STAT_RESPONSE_TIME
101 * MENU_STAT_UNSORTED, superseded by MENU_PACKET_STAT_UNSORTED
102 * MENU_STAT_TELEPHONY, superseded by MENU_TELEPHONY_UNSORTED
103 * MENU_STAT_TELEPHONY_ANSI, superseded by MENU_TELEPHONY_ANSI
104 * MENU_STAT_TELEPHONY_GSM, superseded by MENU_TELEPHONY_GSM
105 * MENU_STAT_TELEPHONY_3GPP_UU, superseded by MENU_TELEPHONY_3GPP_UU
106 * MENU_STAT_TELEPHONY_MTP3, superseded by MENU_TELEPHONY_MTP3
107 * MENU_STAT_TELEPHONY_SCTP, superseded by MENU_TELEPHONY_SCTP
110 const char* name
= luaL_checkstring(L
,WSLUA_ARG_register_menu_NAME
);
111 struct _lua_menu_data
* md
;
113 register_stat_group_t group
= (register_stat_group_t
)wslua_optuint(L
,WSLUA_OPTARG_register_menu_GROUP
,REGISTER_STAT_GROUP_GENERIC
);
115 if ( group
> REGISTER_TOOLS_GROUP_UNSORTED
) {
116 WSLUA_OPTARG_ERROR(register_menu
,GROUP
,"Must be a defined MENU_*");
120 if (!lua_isfunction(L
,WSLUA_ARG_register_menu_ACTION
)) {
121 WSLUA_ARG_ERROR(register_menu
,ACTION
,"Must be a function");
125 md
= g_new(struct _lua_menu_data
, 1);
129 md
->cb_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
132 funnel_register_menu(name
,
142 void wslua_deregister_menus(void) {
143 funnel_deregister_menus(lua_menu_callback
);
147 * Error handler used by lua_custom_packet_menu_callback when calling the user-supplied callback
149 * @param L State of the Lua interpreter
150 * @return Always returns 0
152 static int packet_menu_cb_error_handler(lua_State
* L
) {
153 const char* error
= lua_tostring(L
,1);
154 report_failure("Lua: Error During execution of Packet Menu Callback:\n %s",error
);
159 * Wrapper used to call the user-supplied Lua callback when a custom packet
160 * context menu is clicked.
162 * @param data Lua menu data
163 * @param finfo_array packet data
165 static void lua_custom_packet_menu_callback(void *data
, GPtrArray
*finfo_array
) {
166 // _lua_menu_data is State + the integer index of a callback.
167 struct _lua_menu_data
* md
= (struct _lua_menu_data
*)data
;
168 lua_State
* L
= md
->L
;
171 lua_pushcfunction(L
,packet_menu_cb_error_handler
);
172 lua_rawgeti(L
, LUA_REGISTRYINDEX
, md
->cb_ref
);
174 // Push the packet data as arguments to the Lua callback:
176 for (unsigned i
= 0; i
< finfo_array
->len
; i
++) {
177 field_info
*fi
= (field_info
*)g_ptr_array_index (finfo_array
, i
);
178 push_FieldInfo(L
, fi
);
182 switch ( lua_pcall(L
,items_found
,0,1) ) {
186 g_warning("Runtime error while calling custom_packet_menu callback");
189 g_warning("Memory alloc error while calling custom_packet_menu callback");
192 g_assert_not_reached();
200 * Lua function exposed to users: register_packet_menu
202 WSLUA_FUNCTION
wslua_register_packet_menu(lua_State
* L
) { /* Register a menu item in the packet list. */
203 #define WSLUA_ARG_register_packet_menu_NAME 1 /* The name of the menu item. Use slashes to separate submenus. (e.g. level1/level2/name). (string) */
204 #define WSLUA_ARG_register_packet_menu_ACTION 2 /* The function to be called when the menu item is invoked. The function must take a variable number of arguments and return nothing. The arguments will be FieldInfo objects, one for each field present in the selected packet. */
205 #define WSLUA_OPTARG_register_packet_menu_REQUIRED_FIELDS 3 /* A comma-separated list of packet fields (e.g., http.host,dns.qry.name) which all must be present for the menu to be displayed. If omitted, the packet menu will be displayed for all packets. */
207 const char* name
= luaL_checkstring(L
,WSLUA_ARG_register_packet_menu_NAME
);
208 const char* required_fields
= luaL_optstring(L
,WSLUA_OPTARG_register_packet_menu_REQUIRED_FIELDS
,"");
210 struct _lua_menu_data
* md
;
213 if (!lua_isfunction(L
,WSLUA_ARG_register_packet_menu_ACTION
)) {
214 WSLUA_ARG_ERROR(register_packet_menu
,ACTION
,"Must be a function");
218 md
= g_new0(struct _lua_menu_data
, 1);
222 md
->cb_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
225 funnel_register_packet_menu(name
,
227 lua_custom_packet_menu_callback
,
233 struct _dlg_cb_data
{
238 static int dlg_cb_error_handler(lua_State
* L
) {
239 const char* error
= lua_tostring(L
,1);
240 report_failure("Lua: Error during execution of Dialog callback:\n %s",error
);
244 static void lua_dialog_cb(char** user_input
, void* data
) {
245 struct _dlg_cb_data
* dcbd
= (struct _dlg_cb_data
*)data
;
248 lua_State
* L
= dcbd
->L
;
251 lua_pushcfunction(L
,dlg_cb_error_handler
);
252 lua_rawgeti(L
, LUA_REGISTRYINDEX
, dcbd
->func_ref
);
254 for (i
= 0; (input
= user_input
[i
]) ; i
++) {
255 lua_pushstring(L
,input
);
261 switch ( lua_pcall(L
,i
,0,1) ) {
265 ws_warning("Runtime error while calling dialog callback");
268 ws_warning("Memory alloc error while calling dialog callback");
271 ws_warning("Error while running the error handler function for dialog callback");
274 ws_assert_not_reached();
280 struct _close_cb_data
{
287 static int text_win_close_cb_error_handler(lua_State
* L
) {
288 const char* error
= lua_tostring(L
,1);
289 report_failure("Lua: Error during execution of TextWindow close callback:\n %s",error
);
293 static void text_win_close_cb(void* data
) {
294 struct _close_cb_data
* cbd
= (struct _close_cb_data
*)data
;
295 lua_State
* L
= cbd
->L
;
297 if (cbd
->L
) { /* close function is set */
300 lua_pushcfunction(L
,text_win_close_cb_error_handler
);
301 lua_rawgeti(L
, LUA_REGISTRYINDEX
, cbd
->func_ref
);
303 switch ( lua_pcall(L
,0,0,1) ) {
307 ws_warning("Runtime error during execution of TextWindow close callback");
310 ws_warning("Memory alloc error during execution of TextWindow close callback");
313 ws_warning("Error while running the error handler function for TextWindow close callback");
320 if (cbd
->wslua_tw
->expired
) {
321 g_free(cbd
->wslua_tw
);
324 cbd
->wslua_tw
->expired
= true;
329 WSLUA_FUNCTION
wslua_new_dialog(lua_State
* L
) { /*
330 Displays a dialog, prompting for input. The dialog includes an btn:[OK] button and btn:[Cancel] button. Requires a GUI.
332 .An input dialog in action
333 image::images/wslua-new-dialog.png[{small-screenshot-attrs}]
339 if not gui_enabled() then return end
341 -- Prompt for IP and port and then print them to stdout
342 local label_ip = "IP address"
343 local label_port = "Port"
344 local function print_ip(ip, port)
346 print(label_port, port)
348 new_dialog("Enter IP address", print_ip, label_ip, label_port)
350 -- Prompt for 4 numbers and then print their product to stdout
353 function (a, b, c, d) print(a * b * c * d) end,
358 #define WSLUA_ARG_new_dialog_TITLE 1 /* The title of the dialog. */
359 #define WSLUA_ARG_new_dialog_ACTION 2 /* Action to be performed when the user presses btn:[OK]. */
360 /* WSLUA_MOREARGS new_dialog Strings to be used as labels of the dialog's fields. Each string creates a new labeled field. The first field is required.
361 Instead of a string it is possible to provide tables with fields 'name' and 'value' of type string. Then the created dialog's field will be labeled with the content of name and prefilled with the content of value.*/
364 int top
= lua_gettop(L
);
366 GPtrArray
* field_names
;
367 GPtrArray
* field_values
;
368 struct _dlg_cb_data
* dcbd
;
371 luaL_error(L
,"the GUI facility has to be enabled");
375 if (!ops
->new_dialog
) {
376 WSLUA_ERROR(new_dialog
,"GUI not available");
380 title
= luaL_checkstring(L
,WSLUA_ARG_new_dialog_TITLE
);
382 if (! lua_isfunction(L
,WSLUA_ARG_new_dialog_ACTION
)) {
383 WSLUA_ARG_ERROR(new_dialog
,ACTION
,"Must be a function");
388 WSLUA_ERROR(new_dialog
,"At least one field required");
393 dcbd
= g_new(struct _dlg_cb_data
, 1);
399 dcbd
->func_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
402 field_names
= g_ptr_array_new_with_free_func(g_free
);
403 field_values
= g_ptr_array_new_with_free_func(g_free
);
407 for (i
= 1; i
<= top
; i
++)
409 if (lua_isstring(L
, i
))
411 char* field_name
= g_strdup(luaL_checkstring(L
, i
));
412 char* field_value
= g_strdup("");
413 g_ptr_array_add(field_names
, (void *)field_name
);
414 g_ptr_array_add(field_values
, (void *)field_value
);
416 else if (lua_istable(L
, i
))
418 lua_getfield(L
, i
, "name");
419 lua_getfield(L
, i
, "value");
421 if (!lua_isstring(L
, -2))
425 g_ptr_array_free(field_names
, true);
426 g_ptr_array_free(field_values
, true);
428 WSLUA_ERROR(new_dialog
, "All fields must be strings or a table with a string field 'name'.");
432 char* field_name
= g_strdup(luaL_checkstring(L
, -2));
433 char* field_value
= lua_isstring(L
, -1) ?
434 g_strdup(luaL_checkstring(L
, -1)) :
437 g_ptr_array_add(field_names
, (void *)field_name
);
438 g_ptr_array_add(field_values
, (void *)field_value
);
444 g_ptr_array_free(field_names
, true);
445 g_ptr_array_free(field_values
, true);
447 WSLUA_ERROR(new_dialog
, "All fields must be strings or a table with a string field 'name'.");
452 g_ptr_array_add(field_names
, NULL
);
453 g_ptr_array_add(field_values
, NULL
);
455 ops
->new_dialog(ops
->ops_id
, title
, (const char**)(field_names
->pdata
), (const char**)(field_values
->pdata
), lua_dialog_cb
, dcbd
, g_free
);
457 g_ptr_array_free(field_names
, true);
458 g_ptr_array_free(field_values
, true);
463 WSLUA_CLASS_DEFINE(ProgDlg
,FAIL_ON_NULL("ProgDlg"));
465 Creates and manages a modal progress bar.
466 This is intended to be used with
467 http://lua-users.org/wiki/CoroutinesTutorial[coroutines],
468 where a main UI thread controls the progress bar dialog while a background coroutine (worker thread) yields to the main thread between steps.
469 The main thread checks the status of the btn:[Cancel] button and if it's not set, returns control to the coroutine.
471 .A progress bar in action
472 image::images/wslua-progdlg.png[{medium-screenshot-attrs}]
474 The legacy (GTK+) user interface displayed this as a separate dialog, hence the “Dlg” suffix.
475 The Qt user interface shows a progress bar inside the main status bar.
478 WSLUA_CONSTRUCTOR
ProgDlg_new(lua_State
* L
) { /*
479 Creates and displays a new `ProgDlg` progress bar with a btn:[Cancel] button and optional title.
480 It is highly recommended that you wrap code that uses a `ProgDlg` instance because it does not automatically close itself upon encountering an error.
487 if not gui_enabled() then return end
489 local p = ProgDlg.new("Constructing", "tacos")
491 -- We have to wrap the ProgDlg code in a pcall in case some unexpected
493 local ok, errmsg = pcall(function()
494 local co = coroutine.create(
499 coroutine.yield(i/limit, "step "..i.." of "..limit)
504 -- Whenever coroutine yields, check the status of the cancel button to determine
505 -- when to break. Wait up to 20 sec for coroutine to finish.
506 local start_time = os.time()
507 while coroutine.status(co) ~= 'dead' do
508 local elapsed = os.time() - start_time
510 -- Quit if cancel button pressed or 20 seconds elapsed
511 if p:stopped() or elapsed > 20 then
515 local res, val, val2 = coroutine.resume(co)
516 if not res or res == false then
520 print('coroutine error')
524 -- show progress in progress dialog
531 if not ok and errmsg then
532 report_failure(errmsg)
536 #define WSLUA_OPTARG_ProgDlg_new_TITLE 1 /* Title of the progress bar. Defaults to "Progress". */
537 #define WSLUA_OPTARG_ProgDlg_new_TASK 2 /* Optional task name, which will be appended to the title. Defaults to the empty string (""). */
538 ProgDlg pd
= (ProgDlg
)g_malloc(sizeof(struct _wslua_progdlg
));
539 pd
->title
= g_strdup(luaL_optstring(L
,WSLUA_OPTARG_ProgDlg_new_TITLE
,"Progress"));
540 pd
->task
= g_strdup(luaL_optstring(L
,WSLUA_OPTARG_ProgDlg_new_TASK
,""));
543 if (ops
->new_progress_window
) {
544 pd
->pw
= ops
->new_progress_window(ops
->ops_id
, pd
->title
, pd
->task
, true, &(pd
->stopped
));
547 WSLUA_ERROR(ProgDlg_new
, "GUI not available");
553 WSLUA_RETURN(1); /* The newly created `ProgDlg` object. */
556 WSLUA_METHOD
ProgDlg_update(lua_State
* L
) { /* Sets the progress dialog's progress bar position based on percentage done. */
557 #define WSLUA_ARG_ProgDlg_update_PROGRESS 2 /* Progress value, e.g. 0.75. Value must be between 0.0 and 1.0 inclusive. */
558 #define WSLUA_OPTARG_ProgDlg_update_TASK 3 /* Task name. Currently ignored. Defaults to empty string (""). */
559 ProgDlg pd
= checkProgDlg(L
,1);
560 double pr
= lua_tonumber(L
,WSLUA_ARG_ProgDlg_update_PROGRESS
);
561 const char* task
= luaL_optstring(L
,WSLUA_OPTARG_ProgDlg_update_TASK
,"");
563 if (!ops
->update_progress
) {
564 WSLUA_ERROR(ProgDlg_update
,"GUI not available");
569 pd
->task
= g_strdup(task
);
571 /* XXX, dead code: pd already dereferenced. should it be: !pd->task?
573 WSLUA_ERROR(ProgDlg_update,"Cannot be called for something not a ProgDlg");
576 if (pr
>= 0.0 && pr
<= 1.0) {
577 ops
->update_progress(pd
->pw
, (float) pr
, task
);
579 WSLUA_ERROR(ProgDlg_update
,"Progress value out of range (must be between 0.0 and 1.0)");
586 WSLUA_METHOD
ProgDlg_stopped(lua_State
* L
) { /* Checks whether the user has pressed the btn:[Cancel] button. */
587 ProgDlg pd
= checkProgDlg(L
,1);
589 lua_pushboolean(L
,pd
->stopped
);
591 WSLUA_RETURN(1); /* Boolean `true` if the user has asked to stop the operation, `false` otherwise. */
596 WSLUA_METHOD
ProgDlg_close(lua_State
* L
) { /* Hides the progress bar. */
597 ProgDlg pd
= checkProgDlg(L
,1);
599 if (!ops
->destroy_progress_window
) {
600 WSLUA_ERROR(ProgDlg_close
,"GUI not available");
605 ops
->destroy_progress_window(pd
->pw
);
612 static int ProgDlg__tostring(lua_State
* L
) {
613 ProgDlg pd
= checkProgDlg(L
,1);
615 lua_pushfstring(L
, "%sstopped",pd
->stopped
?"":"not ");
617 WSLUA_RETURN(1); /* A string specifying whether the Progress Dialog has stopped or not. */
620 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
621 static int ProgDlg__gc(lua_State
* L
) {
622 ProgDlg pd
= toProgDlg(L
,1);
625 if (pd
->pw
&& ops
->destroy_progress_window
) {
626 ops
->destroy_progress_window(pd
->pw
);
631 luaL_error(L
, "ProgDlg__gc has being passed something else!");
638 WSLUA_METHODS ProgDlg_methods
[] = {
639 WSLUA_CLASS_FNREG(ProgDlg
,new),
640 WSLUA_CLASS_FNREG(ProgDlg
,update
),
641 WSLUA_CLASS_FNREG(ProgDlg
,stopped
),
642 WSLUA_CLASS_FNREG(ProgDlg
,close
),
646 WSLUA_META ProgDlg_meta
[] = {
647 WSLUA_CLASS_MTREG(ProgDlg
,tostring
),
651 int ProgDlg_register(lua_State
* L
) {
653 ops
= funnel_get_funnel_ops();
655 WSLUA_REGISTER_CLASS(ProgDlg
);
662 WSLUA_CLASS_DEFINE(TextWindow
,FAIL_ON_NULL_OR_EXPIRED("TextWindow")); /*
664 Creates and manages a text window.
665 The text can be read-only or editable, and buttons can be added below the text.
667 .A text window in action
668 image::images/wslua-textwindow.png[{medium-screenshot-attrs}]
671 /* XXX: button and close callback data is being leaked */
672 /* XXX: lua callback function and TextWindow are not garbage collected because
673 they stay in LUA_REGISTRYINDEX forever */
675 WSLUA_CONSTRUCTOR
TextWindow_new(lua_State
* L
) { /*
676 Creates a new `TextWindow` text window and displays it.
683 if not gui_enabled() then return end
685 -- create new text window and initialize its text
686 local win = TextWindow.new("Log")
687 win:set("Hello world!")
689 -- add buttons to clear text window and to enable editing
690 win:add_button("Clear", function() win:clear() end)
691 win:add_button("Enable edit", function() win:set_editable(true) end)
693 -- add button to change text to uppercase
694 win:add_button("Uppercase", function()
695 local text = win:get_text()
697 win:set(string.upper(text))
701 -- print "closing" to stdout when the user closes the text window
702 win:set_atclose(function() print("closing") end)
706 #define WSLUA_OPTARG_TextWindow_new_TITLE 1 /* Title of the new window. Optional. Defaults to "Untitled Window". */
709 TextWindow tw
= NULL
;
710 struct _close_cb_data
* default_cbd
;
712 if (!ops
->new_text_window
|| !ops
->set_close_cb
) {
713 WSLUA_ERROR(TextWindow_new
,"GUI not available");
717 title
= luaL_optstring(L
,WSLUA_OPTARG_TextWindow_new_TITLE
, "Untitled Window");
718 tw
= g_new(struct _wslua_tw
, 1);
720 tw
->ws_tw
= ops
->new_text_window(ops
->ops_id
, title
);
722 default_cbd
= g_new(struct _close_cb_data
, 1);
724 default_cbd
->L
= NULL
;
725 default_cbd
->func_ref
= 0;
726 default_cbd
->wslua_tw
= tw
;
728 tw
->close_cb_data
= (void *)default_cbd
;
730 ops
->set_close_cb(tw
->ws_tw
,text_win_close_cb
,default_cbd
);
732 pushTextWindow(L
,tw
);
734 WSLUA_RETURN(1); /* The newly created `TextWindow` object. */
737 WSLUA_METHOD
TextWindow_set_atclose(lua_State
* L
) { /* Set the function that will be called when the text window closes. */
738 #define WSLUA_ARG_TextWindow_set_atclose_ACTION 2 /* A Lua function to be executed when the user closes the text window. */
740 TextWindow tw
= checkTextWindow(L
,1);
741 struct _close_cb_data
* cbd
;
743 if (!ops
->set_close_cb
) {
744 WSLUA_ERROR(TextWindow_set_atclose
,"GUI not available");
750 if (! lua_isfunction(L
,2)) {
751 WSLUA_ARG_ERROR(TextWindow_set_atclose
,ACTION
,"Must be a function");
755 cbd
= g_new(struct _close_cb_data
, 1);
758 cbd
->func_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
761 g_free(tw
->close_cb_data
);
762 tw
->close_cb_data
= (void *)cbd
;
764 ops
->set_close_cb(tw
->ws_tw
,text_win_close_cb
,cbd
);
766 /* XXX: this is a bad way to do this - should copy the object on to the stack first */
767 WSLUA_RETURN(1); /* The `TextWindow` object. */
770 WSLUA_METHOD
TextWindow_set(lua_State
* L
) { /* Sets the text to be displayed. */
771 #define WSLUA_ARG_TextWindow_set_TEXT 2 /* The text to be displayed. */
773 TextWindow tw
= checkTextWindow(L
,1);
774 const char* text
= luaL_checkstring(L
,WSLUA_ARG_TextWindow_set_TEXT
);
776 if (!ops
->set_text
) {
777 WSLUA_ERROR(TextWindow_set
,"GUI not available");
781 ops
->set_text(tw
->ws_tw
,text
);
783 /* XXX: this is a bad way to do this - should copy the object on to the stack first */
784 WSLUA_RETURN(1); /* The `TextWindow` object. */
787 WSLUA_METHOD
TextWindow_append(lua_State
* L
) { /* Appends text to the current window contents. */
788 #define WSLUA_ARG_TextWindow_append_TEXT 2 /* The text to be appended. */
789 TextWindow tw
= checkTextWindow(L
,1);
790 const char* text
= luaL_checkstring(L
,WSLUA_ARG_TextWindow_append_TEXT
);
792 if (!ops
->append_text
) {
793 WSLUA_ERROR(TextWindow_append
,"GUI not available");
797 ops
->append_text(tw
->ws_tw
,text
);
799 /* XXX: this is a bad way to do this - should copy the object on to the stack first */
800 WSLUA_RETURN(1); /* The `TextWindow` object. */
803 WSLUA_METHOD
TextWindow_prepend(lua_State
* L
) { /* Prepends text to the current window contents. */
804 #define WSLUA_ARG_TextWindow_prepend_TEXT 2 /* The text to be prepended. */
805 TextWindow tw
= checkTextWindow(L
,1);
806 const char* text
= luaL_checkstring(L
,WSLUA_ARG_TextWindow_prepend_TEXT
);
808 if (!ops
->prepend_text
) {
809 WSLUA_ERROR(TextWindow_prepend
,"GUI not available");
813 ops
->prepend_text(tw
->ws_tw
,text
);
815 /* XXX: this is a bad way to do this - should copy the object on to the stack first */
816 WSLUA_RETURN(1); /* The `TextWindow` object. */
819 WSLUA_METHOD
TextWindow_clear(lua_State
* L
) { /* Erases all of the text in the window. */
820 TextWindow tw
= checkTextWindow(L
,1);
822 if (!ops
->clear_text
) {
823 WSLUA_ERROR(TextWindow_clear
,"GUI not available");
827 ops
->clear_text(tw
->ws_tw
);
829 /* XXX: this is a bad way to do this - should copy the object on to the stack first */
830 WSLUA_RETURN(1); /* The `TextWindow` object. */
833 WSLUA_METHOD
TextWindow_get_text(lua_State
* L
) { /* Get the text of the window. */
834 TextWindow tw
= checkTextWindow(L
,1);
837 if (!ops
->get_text
) {
838 WSLUA_ERROR(TextWindow_get_text
,"GUI not available");
842 text
= ops
->get_text(tw
->ws_tw
);
844 lua_pushstring(L
,text
);
845 WSLUA_RETURN(1); /* The `TextWindow`++'++s text. */
848 WSLUA_METHOD
TextWindow_close(lua_State
* L
) { /* Close the window. */
849 TextWindow tw
= checkTextWindow(L
,1);
851 if (!ops
->destroy_text_window
) {
852 WSLUA_ERROR(TextWindow_get_text
,"GUI not available");
856 ops
->destroy_text_window(tw
->ws_tw
);
862 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */
863 static int TextWindow__gc(lua_State
* L
) {
864 TextWindow tw
= toTextWindow(L
,1);
871 if (ops
->destroy_text_window
) {
872 ops
->destroy_text_window(tw
->ws_tw
);
875 g_free(tw
->close_cb_data
);
882 WSLUA_METHOD
TextWindow_set_editable(lua_State
* L
) { /* Make this text window editable. */
883 #define WSLUA_OPTARG_TextWindow_set_editable_EDITABLE 2 /* `true` to make the text editable, `false` otherwise. Defaults to `true`. */
885 TextWindow tw
= checkTextWindow(L
,1);
886 bool editable
= wslua_optbool(L
,WSLUA_OPTARG_TextWindow_set_editable_EDITABLE
,true);
888 if (!ops
->set_editable
) {
889 WSLUA_ERROR(TextWindow_set_editable
,"GUI not available");
893 ops
->set_editable(tw
->ws_tw
,editable
);
895 WSLUA_RETURN(1); /* The `TextWindow` object. */
898 typedef struct _wslua_bt_cb_t
{
904 static bool wslua_button_callback(funnel_text_window_t
* ws_tw
, void* data
) {
905 wslua_bt_cb_t
* cbd
= (wslua_bt_cb_t
*)data
;
906 lua_State
* L
= cbd
->L
;
907 (void) ws_tw
; /* ws_tw is unused since we need wslua_tw_ref and it is stored in cbd */
910 lua_pushcfunction(L
,dlg_cb_error_handler
);
911 lua_rawgeti(L
, LUA_REGISTRYINDEX
, cbd
->func_ref
);
912 lua_rawgeti(L
, LUA_REGISTRYINDEX
, cbd
->wslua_tw_ref
);
914 switch ( lua_pcall(L
,1,0,1) ) {
918 ws_warning("Runtime error while calling button callback");
921 ws_warning("Memory alloc error while calling button callback");
924 ws_warning("Error while running the error handler function for button callback");
927 ws_assert_not_reached();
934 WSLUA_METHOD
TextWindow_add_button(lua_State
* L
) {
935 /* Adds a button with an action handler to the text window. */
936 #define WSLUA_ARG_TextWindow_add_button_LABEL 2 /* The button label. */
937 #define WSLUA_ARG_TextWindow_add_button_FUNCTION 3 /* The Lua function to be called when the button is pressed. */
938 TextWindow tw
= checkTextWindow(L
,1);
939 const char* label
= luaL_checkstring(L
,WSLUA_ARG_TextWindow_add_button_LABEL
);
944 if (!ops
->add_button
) {
945 WSLUA_ERROR(TextWindow_add_button
,"GUI not available");
949 if (! lua_isfunction(L
,WSLUA_ARG_TextWindow_add_button_FUNCTION
) ) {
950 WSLUA_ARG_ERROR(TextWindow_add_button
,FUNCTION
,"must be a function");
956 if (ops
->add_button
) {
957 fbt
= g_new(funnel_bt_t
, 1);
958 cbd
= g_new(wslua_bt_cb_t
, 1);
961 fbt
->func
= wslua_button_callback
;
963 fbt
->free_fcn
= g_free
;
964 fbt
->free_data_fcn
= g_free
;
967 cbd
->func_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
968 cbd
->wslua_tw_ref
= luaL_ref(L
, LUA_REGISTRYINDEX
);
970 ops
->add_button(tw
->ws_tw
,fbt
,label
);
973 WSLUA_RETURN(1); /* The `TextWindow` object. */
976 WSLUA_METHODS TextWindow_methods
[] = {
977 WSLUA_CLASS_FNREG(TextWindow
,new),
978 WSLUA_CLASS_FNREG(TextWindow
,set
),
979 WSLUA_CLASS_FNREG(TextWindow
,append
),
980 WSLUA_CLASS_FNREG(TextWindow
,prepend
),
981 WSLUA_CLASS_FNREG(TextWindow
,clear
),
982 WSLUA_CLASS_FNREG(TextWindow
,set_atclose
),
983 WSLUA_CLASS_FNREG(TextWindow
,set_editable
),
984 WSLUA_CLASS_FNREG(TextWindow
,get_text
),
985 WSLUA_CLASS_FNREG(TextWindow
,add_button
),
986 WSLUA_CLASS_FNREG(TextWindow
,close
),
990 WSLUA_META TextWindow_meta
[] = {
991 {"__tostring", TextWindow_get_text
},
995 int TextWindow_register(lua_State
* L
) {
997 ops
= funnel_get_funnel_ops();
999 WSLUA_REGISTER_CLASS(TextWindow
);
1005 WSLUA_FUNCTION
wslua_retap_packets(lua_State
* L
) {
1007 Rescans all packets and runs each <<lua_class_Listener, tap listener>> without reconstructing the display.
1009 if ( ops
->retap_packets
) {
1010 ops
->retap_packets(ops
->ops_id
);
1012 WSLUA_ERROR(wslua_retap_packets
, "GUI not available");
1019 WSLUA_FUNCTION
wslua_copy_to_clipboard(lua_State
* L
) { /* Copy a string into the clipboard. Requires a GUI. */
1020 #define WSLUA_ARG_copy_to_clipboard_TEXT 1 /* The string to be copied into the clipboard. */
1021 const char* copied_str
= luaL_checkstring(L
,WSLUA_ARG_copy_to_clipboard_TEXT
);
1023 if (!ops
->copy_to_clipboard
) {
1024 WSLUA_ERROR(copy_to_clipboard
, "GUI not available");
1028 gstr
= g_string_new(copied_str
);
1030 ops
->copy_to_clipboard(gstr
);
1032 g_string_free(gstr
,TRUE
);
1037 WSLUA_FUNCTION
wslua_open_capture_file(lua_State
* L
) { /* Open and display a capture file. Requires a GUI. */
1038 #define WSLUA_ARG_open_capture_file_FILENAME 1 /* The name of the file to be opened. */
1039 #define WSLUA_ARG_open_capture_file_FILTER 2 /* The https://gitlab.com/wireshark/wireshark/-/wikis/DisplayFilters[display filter] to be applied once the file is opened. */
1041 const char* fname
= luaL_checkstring(L
,WSLUA_ARG_open_capture_file_FILENAME
);
1042 const char* filter
= luaL_optstring(L
,WSLUA_ARG_open_capture_file_FILTER
,NULL
);
1045 if (!ops
->open_file
) {
1046 WSLUA_ERROR(open_capture_file
, "GUI not available");
1050 if (! ops
->open_file(ops
->ops_id
, fname
, filter
, &error
) ) {
1051 lua_pushboolean(L
,false);
1054 lua_pushstring(L
,error
);
1061 lua_pushboolean(L
,true);
1066 WSLUA_FUNCTION
wslua_get_filter(lua_State
* L
) { /* Get the main filter text. */
1067 const char *filter_str
= NULL
;
1069 if (!ops
->get_filter
) {
1070 WSLUA_ERROR(get_filter
, "GUI not available");
1074 filter_str
= ops
->get_filter(ops
->ops_id
);
1075 lua_pushstring(L
,filter_str
);
1080 WSLUA_FUNCTION
wslua_set_filter(lua_State
* L
) { /* Set the main filter text. */
1081 #define WSLUA_ARG_set_filter_TEXT 1 /* The filter's text. */
1082 const char* filter_str
= luaL_checkstring(L
,WSLUA_ARG_set_filter_TEXT
);
1084 if (!ops
->set_filter
) {
1085 WSLUA_ERROR(set_filter
, "GUI not available");
1089 ops
->set_filter(ops
->ops_id
, filter_str
);
1094 WSLUA_FUNCTION
wslua_get_color_filter_slot(lua_State
* L
) { /*
1095 Gets the current https://gitlab.com/wireshark/wireshark/-/wikis/ColoringRules[packet coloring rule] (by index) for the
1096 current session. Wireshark reserves 10 slots for these coloring rules. Requires a GUI.
1098 #define WSLUA_ARG_get_color_filter_slot_ROW 1 /*
1099 The index (1-10) of the desired color filter value in the temporary coloring rules list.
1101 .Default background colors
1102 [cols="3",options="header"]
1104 |Index |RGB (hex) |Color
1105 |1 |ffc0c0 |{set:cellbgcolor:#ffc0c0} pink 1
1106 |2 |ffc0ff |{set:cellbgcolor:#ffc0ff} pink 2
1107 |3 |e0c0e0 |{set:cellbgcolor:#e0c0e0} purple 1
1108 |4 |c0c0ff |{set:cellbgcolor:#c0c0ff} purple 2
1109 |5 |c0e0e0 |{set:cellbgcolor:#c0e0e0} green 1
1110 |6 |c0ffff |{set:cellbgcolor:#c0ffff} green 2
1111 |7 |c0ffc0 |{set:cellbgcolor:#c0ffc0} green 3
1112 |8 |ffffc0 |{set:cellbgcolor:#ffffc0} yellow 1
1113 |9 |e0e0c0 |{set:cellbgcolor:#e0e0c0} yellow 2
1114 |10 |e0e0e0 |{set:cellbgcolor:#e0e0e0} gray
1117 uint8_t row
= (uint8_t)luaL_checkinteger(L
, WSLUA_ARG_get_color_filter_slot_ROW
);
1118 char* filter_str
= NULL
;
1120 if (!ops
->get_color_filter_slot
) {
1121 WSLUA_ERROR(get_color_filter_slot
, "GUI not available");
1125 filter_str
= ops
->get_color_filter_slot(row
);
1126 if (filter_str
== NULL
) {
1129 lua_pushstring(L
, filter_str
);
1136 WSLUA_FUNCTION
wslua_set_color_filter_slot(lua_State
* L
) { /*
1137 Sets a https://gitlab.com/wireshark/wireshark/-/wikis/ColoringRules[packet coloring rule] (by index) for the current session.
1138 Wireshark reserves 10 slots for these coloring rules.
1141 #define WSLUA_ARG_set_color_filter_slot_ROW 1 /*
1142 The index (1-10) of the desired color in the temporary coloring rules list.
1143 The default foreground is black and the default backgrounds are listed below.
1145 // XXX We need get the colors working, e.g. by adding them to a stylesheet.
1146 .Default background colors
1147 [cols="3",options="header"]
1149 |Index |RGB (hex) |Color
1150 |1 |ffc0c0 |{set:cellbgcolor:#ffc0c0} pink 1
1151 |2 |ffc0ff |{set:cellbgcolor:#ffc0ff} pink 2
1152 |3 |e0c0e0 |{set:cellbgcolor:#e0c0e0} purple 1
1153 |4 |c0c0ff |{set:cellbgcolor:#c0c0ff} purple 2
1154 |5 |c0e0e0 |{set:cellbgcolor:#c0e0e0} green 1
1155 |6 |c0ffff |{set:cellbgcolor:#c0ffff} green 2
1156 |7 |c0ffc0 |{set:cellbgcolor:#c0ffc0} green 3
1157 |8 |ffffc0 |{set:cellbgcolor:#ffffc0} yellow 1
1158 |9 |e0e0c0 |{set:cellbgcolor:#e0e0c0} yellow 2
1159 |10 |e0e0e0 |{set:cellbgcolor:#e0e0e0} gray
1162 The color list can be set from the command line using two unofficial preferences: `gui.colorized_frame.bg` and `gui.colorized_frame.fg`, which require 10 hex RGB codes (6 hex digits each), e.g.
1164 wireshark -o gui.colorized_frame.bg:${RGB0},${RGB1},${RGB2},${RGB3},${RGB4},${RGB5},${RGB6},${RGB7},${RGB8},${RGB9}
1167 For example, this command yields the same results as the table above (and with all foregrounds set to black):
1169 wireshark -o gui.colorized_frame.bg:ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0 -o gui.colorized_frame.fg:000000,000000,000000,000000,000000,000000,000000,000000,000000,000000
1172 #define WSLUA_ARG_set_color_filter_slot_TEXT 2 /* The https://gitlab.com/wireshark/wireshark/-/wikis/DisplayFilters[display filter] for selecting packets to be colorized
1174 uint8_t row
= (uint8_t)luaL_checkinteger(L
,WSLUA_ARG_set_color_filter_slot_ROW
);
1175 const char* filter_str
= luaL_checkstring(L
,WSLUA_ARG_set_color_filter_slot_TEXT
);
1177 if (!ops
->set_color_filter_slot
) {
1178 WSLUA_ERROR(set_color_filter_slot
, "GUI not available");
1182 ops
->set_color_filter_slot(row
, filter_str
);
1187 WSLUA_FUNCTION
wslua_apply_filter(lua_State
* L
) { /*
1188 Apply the filter in the main filter box.
1193 Avoid calling this from within a dissector function or else an infinite loop can occur if it causes the dissector to be called again.
1194 This function is best used in a button callback (from a dialog or text window) or menu callback.
1197 if (!ops
->apply_filter
) {
1198 WSLUA_ERROR(apply_filter
, "GUI not available");
1202 ops
->apply_filter(ops
->ops_id
);
1208 WSLUA_FUNCTION
wslua_reload(lua_State
* L
) { /* Reload the current capture file. Deprecated. Use reload_packets() instead. */
1210 if (!ops
->reload_packets
) {
1211 WSLUA_ERROR(reload
, "GUI not available");
1215 ops
->reload_packets(ops
->ops_id
);
1221 WSLUA_FUNCTION
wslua_reload_packets(lua_State
* L
) { /*
1222 Reload the current capture file.
1227 Avoid calling this from within a dissector function or else an infinite loop can occur if it causes the dissector to be called again.
1228 This function is best used in a button callback (from a dialog or text window) or menu callback.
1232 if (!ops
->reload_packets
) {
1233 WSLUA_ERROR(reload
, "GUI not available");
1237 ops
->reload_packets(ops
->ops_id
);
1243 WSLUA_FUNCTION
wslua_redissect_packets(lua_State
* L
) { /*
1244 Redissect all packets in the current capture file.
1249 Avoid calling this from within a dissector function or else an infinite loop can occur if it causes the dissector to be called again.
1250 This function is best used in a button callback (from a dialog or text window) or menu callback.
1254 if (!ops
->redissect_packets
) {
1255 WSLUA_ERROR(reload
, "GUI not available");
1259 ops
->redissect_packets(ops
->ops_id
);
1265 WSLUA_FUNCTION
wslua_reload_lua_plugins(lua_State
* L
) { /* Reload all Lua plugins. */
1267 if (!ops
->reload_lua_plugins
) {
1268 WSLUA_ERROR(reload_lua_plugins
, "GUI not available");
1272 ops
->reload_lua_plugins(ops
->ops_id
);
1278 WSLUA_FUNCTION
wslua_browser_open_url(lua_State
* L
) { /*
1279 Opens an URL in a web browser. Requires a GUI.
1283 Do not pass an untrusted URL to this function.
1285 It will be passed to the system's URL handler, which might execute malicious code, switch on your Bluetooth-connected foghorn, or any of a number of unexpected or harmful things.
1288 #define WSLUA_ARG_browser_open_url_URL 1 /* The url. */
1289 const char* url
= luaL_checkstring(L
,WSLUA_ARG_browser_open_url_URL
);
1291 if (!ops
->browser_open_url
) {
1292 WSLUA_ERROR(browser_open_url
, "GUI not available");
1296 ops
->browser_open_url(url
);
1301 WSLUA_FUNCTION
wslua_browser_open_data_file(lua_State
* L
) { /*
1302 Open a file located in the data directory (specified in the Wireshark preferences) in the web browser.
1303 If the file does not exist, the function silently ignores the request.
1308 Do not pass an untrusted URL to this function.
1310 It will be passed to the system's URL handler, which might execute malicious code, switch on your Bluetooth-connected foghorn, or any of a number of unexpected or harmful things.
1313 #define WSLUA_ARG_browser_open_data_file_FILENAME 1 /* The file name. */
1314 const char* file
= luaL_checkstring(L
,WSLUA_ARG_browser_open_data_file_FILENAME
);
1316 if (!ops
->browser_open_data_file
) {
1317 WSLUA_ERROR(browser_open_data_file
, "GUI not available");
1321 ops
->browser_open_data_file(file
);
1327 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1332 * indent-tabs-mode: nil
1335 * vi: set shiftwidth=4 tabstop=8 expandtab:
1336 * :indentSize=4:tabSize=8:noTabs=true: