Qt: Add interface toolbar support

An extcap utility can provide configuration for controls to use in a
GUI interface toolbar.  This controls are bidirectional and can be
used to control the extcap utility while capturing.

This is useful in scenarios where configuration can be done based on
findings in the capture process, setting temporary values or give other
inputs without restarting current capture.

Todo:
- Add support for Windows

Change-Id: Ie15fa67f92eb27d8b73df6bb36f66b9a7d81932d
Reviewed-on: https://code.wireshark.org/review/19982
Petri-Dish: Stig Bjørlykke <stig@bjorlykke.org>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Stig Bjørlykke <stig@bjorlykke.org>
This commit is contained in:
Stig Bjørlykke 2017-04-15 23:30:30 +02:00
parent cd55bd2925
commit 77751c94f1
30 changed files with 2647 additions and 27 deletions

View File

@ -68,6 +68,8 @@ capture_opts_init(capture_options *capture_opts)
capture_opts->default_options.extcap_args = NULL;
capture_opts->default_options.extcap_userdata = NULL;
capture_opts->default_options.extcap_pid = INVALID_EXTCAP_PID;
capture_opts->default_options.extcap_control_in = NULL;
capture_opts->default_options.extcap_control_out = NULL;
#endif
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
capture_opts->default_options.buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
@ -702,6 +704,8 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
interface_opts.extcap_args = NULL;
interface_opts.extcap_pid = INVALID_EXTCAP_PID;
interface_opts.extcap_userdata = NULL;
interface_opts.extcap_control_in = g_strdup(capture_opts->default_options.extcap_control_in);
interface_opts.extcap_control_out = g_strdup(capture_opts->default_options.extcap_control_out);
#endif
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
interface_opts.buffer_size = capture_opts->default_options.buffer_size;
@ -1129,6 +1133,8 @@ capture_opts_del_iface(capture_options *capture_opts, guint if_index)
if (interface_opts.extcap_pid != INVALID_EXTCAP_PID)
g_spawn_close_pid(interface_opts.extcap_pid);
g_free(interface_opts.extcap_userdata);
g_free(interface_opts.extcap_control_in);
g_free(interface_opts.extcap_control_out);
#endif
#ifdef HAVE_PCAP_REMOTE
if (interface_opts.src_type == CAPTURE_IFREMOTE) {
@ -1180,6 +1186,8 @@ collect_ifaces(capture_options *capture_opts)
if (interface_opts.extcap_args)
g_hash_table_ref(interface_opts.extcap_args);
interface_opts.extcap_userdata = NULL;
interface_opts.extcap_control_in = NULL;
interface_opts.extcap_control_out = NULL;
#endif
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
interface_opts.buffer_size = device.buffer;

View File

@ -226,6 +226,8 @@ typedef struct interface_options_tag {
GPid extcap_pid; /* pid of running process or INVALID_EXTCAP_PID */
gpointer extcap_userdata;
guint extcap_child_watch;
gchar *extcap_control_in;
gchar *extcap_control_out;
#endif
#ifdef CAN_SET_CAPTURE_BUFFER_SIZE
int buffer_size;

View File

@ -196,6 +196,195 @@ such a check is the same as for Qt RegExp classes. This feature is only active i
Qt version of Wireshark.
TOOLBAR CONTROLS
================
An extcap utility can provide configuration for controls to use in an interface toolbar.
This controls are bidirectional and can be used to control the extcap utility while
capturing.
This is useful in scenarios where configuration can be done based on findings in the
capture process, setting temporary values or give other inputs without restarting the
current capture.
Example:
$ extcapbin --extcap-interfaces
extcap {version=1.0}{display=Example extcap interface}
interface {value=example1}{display=Example interface 1 for extcap}
interface {value=example2}{display=Example interface 2 for extcap}
control {number=0}{type=string}{display=Message}{tooltip=Package message content. Must start with a capital letter.}{validation=[A-Z]+}{required=true}
control {number=1}{type=selector}{display=Time delay}{tooltip=Time delay between packages}
control {number=2}{type=boolean}{display=Verify}{default=true}{tooltip=Verify package content}
control {number=3}{type=button}{display=Turn on}{tooltip=Turn on or off}
control {number=4}{type=button}{role=logger}{display=Log}{tooltip=Show capture log}
value {control=1}{value=1}{display=1 sec}
value {control=1}{value=2}{display=2 sec}{default=true}
All controls will be presented as GUI elements in a toolbar specific to the extcap
utility. The extcap must not rely on using those controls (they are optional) because
of other capturing tools not using GUI (e.g. tshark, tfshark).
CONTROLS
========
The controls are similar to the ARGUMENTS, but without the CALL element. All controls
may be given a default value at startup and most can be changed during capture, both
by the extcap and the user (depending on the type of control).
All controls must provide a NUMBER, by which they are identified. No NUMBER may be
provided twice. Also all options must present the elements TYPE and DISPLAY, where
TYPE provides the type of control to add to the toolbar and DISPLAY the name in the GUI.
Additionally TOOLTIP and PLACEHOLDER may be provided, which will give the user an
explanation within the GUI.
All controls, except from the logger, help and reset buttons, may be disabled
(and enabled) in GUI by the extcap during capture. This can be because of set-once
operations, or operations which takes some time to complete.
All control values which are changed by the user (not equal to the default value) will
be sent to the extcap utility when starting a capture. The extcap utility may choose
to discard initial values and set new values, depending on implementation.
This TYPEs are defined as controls:
* BOOLEAN - This provides a checkbox with the possibility to set a true/false value.
The extcap utility can set a default value at startup, and can change (set) and receive
value changes while capturing. When starting a capture the GUI will send the value if
different from the default value.
The payload is one byte with binary value 0 or 1.
Valid Commands: Set value, Enable, Disable.
* BUTTON - This provides a button with different ROLEs:
** CONTROL - This button will send a signal.
This is the default role if nothing is configured.
The extcap utility can set the button text at startup, and can change (set) the
button text and receive button press signals while capturing. The button is
disabled and the button text is restored to the default text when not capturing.
The payload is either the button text or empty (signal).
Valid Commands: Set value, Enable, Disable.
** LOGGER - This provides a logger mechanism where the extcap utility can send log
entries to be presented in a log window. This communication is unidirectional.
The payload is the log entry, and should be ended with a newline.
Maximum length is 65535 bytes.
Valid Commands: Set log entry, Add log entry.
The Set command will clear the log before adding the entry.
** HELP - This button opens the help page, if configured.
This type has no controls and will not be used in communication.
Valid Commands: NONE.
** RESET - This button will restore all control values to default.
This type has no controls and will not be used in communication.
Valid Commands: NONE.
* SELECTOR - This provides a combo box with fixed values which can be selected.
The extcap utility can set default values at startup, and add and remove values and
receive change in value selection while capturing. When starting a capture the GUI
will send the value if different from the default value.
The payload is a string with the value, and optionally a string with a display
value if this is different from the value. This two string values are separated
by a null character.
Valid Commands: Set selected value, Add value, Remove value, Enable, Disable.
If value is empty the Remove command will remove all entries.
* STRING - This provides a text edit line with the possibility to set a string or any
value which can be represented in a string (integer, float, date, etc.).
The extcap utility can set a default string value at startup, and can change (set) and
receive value changes while capturing. When starting a capture the GUI will send the
value if different from the default value.
The payload is a string with the value. Maximum length is 32767 bytes.
Valid Commands: Set value, Enable, Disable.
The element VALIDATION allows to provide a regular expression string, which is used
to check the user input for validity beyond normal data type or range checks.
Back-slashes must be escaped (as in \\b for \b).
MESSAGES
========
In addition to the controls it's possible to send a single message from the extcap
utility to the user. This message can be put in the status bar or displayed in a
information, warning or error dialog which must be accepted by the user. This message
does not use the NUMBER argument so this can have any value.
CONTROL PROTOCOL
================
The protocol used to communicate over the control pipes has a fixed size header of
6 bytes and a payload with 0 - 65535 bytes.
Control packet:
+----+----+----+----+----+----+----+----+
| Sync Pipe Indication (1 byte) |
+----+----+----+----+----+----+----+----+
| Message Length |
| (3 bytes network order) |
+----+----+----+----+----+----+----+----+
| Control Number (1 byte) |
+----+----+----+----+----+----+----+----+
| Command (1 byte) |
+----+----+----+----+----+----+----+----+
| Payload |
| (0 - 65535 bytes) |
+----+----+----+----+----+----+----+----+
Sync Pipe Indication:
The common sync pipe indication. This protocol uses the value 'T'.
Message Length:
Payload length + 2 bytes for argument number and command.
Control Number:
Unique number to identify the control. This number also gives the order of
the controls in the interface toolbar.
Command: Control type:
0 = Initialized none
1 = Set boolean / button / logger / selector / string
2 = Add logger / selector
3 = Remove selector
4 = Enable boolean / button / selector / string
5 = Disable boolean / button / selector / string
6 = Statusbar message none
7 = Information message none
8 = Warning message none
9 = Error message none
Payload Length:
The length of the following payload. Maximum length is 65535 bytes.
The Initialized command will be sent from the GUI to the extcap utility when all
initial control values are sent after starting a capture. This is an indication
that the GUI is ready to receive control values.
The GUI will only send Initialized and Set commands. The extcap utility shall not
send the Initialized command.
Messages with unknown control number or command will be silently ignored.
DEVELOPMENT
===========
To have extcap support, extcap must be enabled. Moreover the specific extcap must

View File

@ -51,13 +51,38 @@ import struct
import binascii
from threading import Thread
ERROR_USAGE = 0
ERROR_ARG = 1
ERROR_INTERFACE = 2
ERROR_FIFO = 3
ERROR_DELAY = 4
ERROR_USAGE = 0
ERROR_ARG = 1
ERROR_INTERFACE = 2
ERROR_FIFO = 3
ERROR_DELAY = 4
globalinterface = 0
CTRL_CMD_INITIALIZED = 0
CTRL_CMD_SET = 1
CTRL_CMD_ADD = 2
CTRL_CMD_REMOVE = 3
CTRL_CMD_ENABLE = 4
CTRL_CMD_DISABLE = 5
CTRL_CMD_STATUSBAR = 6
CTRL_CMD_INFORMATION = 7
CTRL_CMD_WARNING = 8
CTRL_CMD_ERROR = 9
CTRL_ARG_MESSAGE = 0
CTRL_ARG_DELAY = 1
CTRL_ARG_VERIFY = 2
CTRL_ARG_BUTTON = 3
CTRL_ARG_HELP = 4
CTRL_ARG_RESET = 5
CTRL_ARG_LOGGER = 6
CTRL_ARG_NONE = 255
initialized = False
message = ''
delay = 0.0
verify = False
button = False
button_disabled = False
"""
This code has been taken from http://stackoverflow.com/questions/5943249/python-argparse-and-controlling-overriding-the-exit-status-code - originally developed by Rob Cowie http://stackoverflow.com/users/46690/rob-cowie
@ -128,12 +153,29 @@ def extcap_config(interface):
def extcap_interfaces():
print ("extcap {version=1.0}{help=http://www.wireshark.org}")
print ("interface {value=example1}{display=Example interface usage for extcap}")
print ("extcap {version=1.0}{help=http://www.wireshark.org}{display=Example extcap interface}")
print ("interface {value=example1}{display=Example interface 1 for extcap}")
print ("interface {value=example2}{display=Example interface 2 for extcap}")
print ("control {number=%d}{type=string}{display=Message}{tooltip=Package message content. Must start with a capital letter.}{placeholder=Enter package message content here ...}{validation=^[A-Z]+}" % CTRL_ARG_MESSAGE)
print ("control {number=%d}{type=selector}{display=Time delay}{tooltip=Time delay between packages}" % CTRL_ARG_DELAY)
print ("control {number=%d}{type=boolean}{display=Verify}{default=true}{tooltip=Verify package content}" % CTRL_ARG_VERIFY)
print ("control {number=%d}{type=button}{display=Turn on}{tooltip=Turn on or off}" % CTRL_ARG_BUTTON)
print ("control {number=%d}{type=button}{role=help}{display=Help}{tooltip=Show help}" % CTRL_ARG_HELP)
print ("control {number=%d}{type=button}{role=reset}{display=Reset}{tooltip=Restore default values}" % CTRL_ARG_RESET)
print ("control {number=%d}{type=button}{role=logger}{display=Log}{tooltip=Show capture log}" % CTRL_ARG_LOGGER)
print ("value {control=%d}{value=1}{display=1}" % CTRL_ARG_DELAY)
print ("value {control=%d}{value=2}{display=2}" % CTRL_ARG_DELAY)
print ("value {control=%d}{value=3}{display=3}" % CTRL_ARG_DELAY)
print ("value {control=%d}{value=4}{display=4}" % CTRL_ARG_DELAY)
print ("value {control=%d}{value=5}{display=5}{default=true}" % CTRL_ARG_DELAY)
print ("value {control=%d}{value=60}{display=60}" % CTRL_ARG_DELAY)
def extcap_dlts(interface):
if ( interface == '1' ):
print ("dlt {number=147}{name=USER0}{display=Demo Implementation for Extcap}")
elif ( interface == '2' ):
print ("dlt {number=148}{name=USER1}{display=Demo Implementation for Extcap}")
"""
@ -216,20 +258,125 @@ def pcap_fake_package ( message, fake_ip ):
pcap += message
return pcap
def extcap_capture(interface, fifo, delay, verify, message, remote, fake_ip):
tdelay = delay if delay != 0 else 5
def control_read(fn):
try:
header = fn.read(6)
sp, _, length, arg, typ = struct.unpack('>sBHBB', header)
if length > 2:
payload = fn.read(length - 2)
else:
payload = ''
return arg, typ, payload
except:
return None, None, None
def control_read_thread(control_in, fn_out):
global initialized, message, delay, verify, button, button_disabled
with open(control_in, 'rb', 0 ) as fn:
arg = 0
while arg != None:
arg, typ, payload = control_read(fn)
log = ''
if typ == CTRL_CMD_INITIALIZED:
initialized = True
elif arg == CTRL_ARG_MESSAGE:
message = payload
log = "Message = " + payload
elif arg == CTRL_ARG_DELAY:
delay = float(payload)
log = "Time delay = " + payload
elif arg == CTRL_ARG_VERIFY:
# Only read this after initialized
if initialized:
verify = (payload[0] != '\0')
log = "Verify = " + str(verify)
control_write(fn_out, CTRL_ARG_NONE, CTRL_CMD_STATUSBAR, "Verify changed")
elif arg == CTRL_ARG_BUTTON:
control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_DISABLE, "")
button_disabled = True
if button == True:
control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_SET, "Turn on")
button = False
log = "Button turned off"
else:
control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_SET, "Turn off")
button = True
log = "Button turned on"
if len(log) > 0:
control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_ADD, log + "\n")
def control_write(fn, arg, typ, payload):
packet = bytearray()
packet += struct.pack('>sBHBB', 'T', 0, len(payload) + 2, arg, typ)
packet += payload
fn.write(packet)
def control_write_defaults(fn_out):
global initialized, message, delay, verify
while not initialized:
time.sleep(.1) # Wait for initial control values
# Write startup configuration to Toolbar controls
control_write(fn_out, CTRL_ARG_MESSAGE, CTRL_CMD_SET, message)
control_write(fn_out, CTRL_ARG_DELAY, CTRL_CMD_SET, str(delay))
control_write(fn_out, CTRL_ARG_VERIFY, CTRL_CMD_SET, struct.pack('B', verify))
for i in range(1,16):
item = bytearray()
item += str(i) + struct.pack('B', 0) + str(i) + " sec"
control_write(fn_out, CTRL_ARG_DELAY, CTRL_CMD_ADD, item)
control_write(fn_out, CTRL_ARG_DELAY, CTRL_CMD_REMOVE, str(60))
def extcap_capture(interface, fifo, control_in, control_out, in_delay, in_verify, in_message, remote, fake_ip):
global message, delay, verify, button_disabled
delay = in_delay if in_delay != 0 else 5
message = in_message
verify = in_verify
counter = 1
if not os.path.exists(fifo):
print ( "Fifo does not exist, exiting!", file=sys.stderr )
sys.exit(1)
fn_out = None
if control_out != None:
fn_out = open(control_out, 'wb', 0)
control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_SET, "Log started at " + time.strftime("%c") + "\n")
if control_in != None:
# Start reading thread
thread = Thread(target = control_read_thread, args = (control_in, fn_out))
thread.start()
if fn_out != None:
control_write_defaults(fn_out)
with open(fifo, 'wb', 0 ) as fh:
fh.write (pcap_fake_header())
while True:
if fn_out != None:
log = "Received packet #" + str(counter) + "\n"
control_write(fn_out, CTRL_ARG_LOGGER, CTRL_CMD_ADD, log)
counter = counter + 1
if button_disabled == True:
control_write(fn_out, CTRL_ARG_BUTTON, CTRL_CMD_ENABLE, "")
control_write(fn_out, CTRL_ARG_NONE, CTRL_CMD_INFORMATION, "Turn action finished.")
button_disabled = False
out = ("%s|%04X%s|%s" % ( remote.strip(), len(message), message, verify )).encode("utf8")
fh.write (pcap_fake_package(out, fake_ip))
time.sleep(tdelay)
time.sleep(delay)
thread.join()
if fn_out != None:
fn_out.close()
def extcap_close_fifo(fifo):
if not os.path.exists(fifo):
@ -268,6 +415,8 @@ if __name__ == '__main__':
parser.add_argument("--extcap-config", help="Provide a list of configurations for the given interface", action="store_true")
parser.add_argument("--extcap-capture-filter", help="Used together with capture to provide a capture filter")
parser.add_argument("--fifo", help="Use together with capture to provide the fifo to dump data to")
parser.add_argument("--extcap-control-in", help="Use together with capture to provide the fifo to dump data to")
parser.add_argument("--extcap-control-out", help="Use together with capture to provide the fifo to dump data to")
# Interface Arguments
parser.add_argument("--verify", help="Demonstrates a verification bool flag", action="store_true" )
@ -334,7 +483,7 @@ if __name__ == '__main__':
sys.exit(ERROR_DELAY)
try:
extcap_capture(interface, args.fifo, args.delay, args.verify, message, args.remote, fake_ip)
extcap_capture(interface, args.fifo, args.extcap_control_in, args.extcap_control_out, args.delay, args.verify, message, args.remote, fake_ip)
except KeyboardInterrupt:
pass
else:

View File

@ -48,6 +48,8 @@ since version 2.2.0:
* You can move back and forth in the selection history in the Qt UI.
* IEEE 802.15.4 dissector now uses an UAT for decryption keys. The original
decryption key preference has been obsoleted.
* Extcap utilities can now provide configuration for a GUI interface toolbar to
control the extcap utility while capturing.
//=== Removed Dissectors

171
extcap.c
View File

@ -49,6 +49,8 @@
#include <epan/prefs.h>
#include "ui/iface_toolbar.h"
#include <wsutil/file_util.h>
#include <wsutil/filesystem.h>
#include <wsutil/tempfile.h>
@ -77,6 +79,11 @@ static GHashTable * _loaded_interfaces = NULL;
*/
static GHashTable * _tool_for_ifname = NULL;
/* internal container, for all the extcap executables that have been found
* and that provides a toolbar with controls to be added to a Interface Toolbar
*/
static GHashTable *_toolbars = NULL;
/* internal container, to map preference names to pointers that hold preference
* values. These ensure that preferences can survive extcap if garbage
* collection, and does not lead to dangling pointers in the prefs subsystem.
@ -198,6 +205,56 @@ extcap_find_interface_for_ifname(const gchar *ifname)
return result;
}
static void
extcap_free_toolbar_value(iface_toolbar_value *value)
{
if (!value)
{
return;
}
g_free(value->value);
g_free(value->display);
g_free(value);
}
static void
extcap_free_toolbar_control(iface_toolbar_control *control)
{
if (!control)
{
return;
}
g_free(control->display);
g_free(control->validation);
g_free(control->tooltip);
if (control->ctrl_type == INTERFACE_TYPE_STRING) {
g_free(control->default_value.string);
}
g_list_foreach(control->values, (GFunc)extcap_free_toolbar_value, NULL);
g_list_free(control->values);
g_free(control);
}
static void
extcap_free_toolbar(gpointer data)
{
if (!data)
{
return;
}
iface_toolbar *toolbar = (iface_toolbar *)data;
g_free(toolbar->menu_title);
g_free(toolbar->help);
g_list_free_full(toolbar->ifnames, g_free);
g_list_foreach(toolbar->controls, (GFunc)extcap_free_toolbar_control, NULL);
g_list_free(toolbar->controls);
g_free(toolbar);
}
static gboolean
extcap_if_exists_for_extcap(const gchar *ifname, const gchar *extcap)
{
@ -218,6 +275,26 @@ extcap_if_executable(const gchar *ifname)
return interface != NULL ? interface->extcap_path : NULL;
}
static void
extcap_iface_toolbar_add(const gchar *extcap, iface_toolbar *toolbar_entry)
{
char *toolname;
if (!extcap || !toolbar_entry)
{
return;
}
toolname = g_path_get_basename(extcap);
if (!g_hash_table_lookup(_toolbars, toolname))
{
g_hash_table_insert(_toolbars, g_strdup(toolname), toolbar_entry);
}
g_free(toolname);
}
/* Note: args does not need to be NULL-terminated. */
static gboolean extcap_foreach(gint argc, gchar **args,
extcap_cb_t cb, extcap_callback_info_t cb_info)
@ -815,6 +892,27 @@ extcap_has_configuration(const char *ifname, gboolean is_required)
return found;
}
gboolean
extcap_has_toolbar(const char *ifname)
{
if (!iface_toolbar_use())
{
return FALSE;
}
GList *toolbar_list = g_hash_table_get_values (_toolbars);
for (GList *walker = toolbar_list; walker; walker = walker->next)
{
iface_toolbar *toolbar = (iface_toolbar *) walker->data;
if (g_list_find_custom(toolbar->ifnames, ifname, (GCompareFunc) strcmp))
{
return TRUE;
}
}
return FALSE;
}
/* taken from capchild/capture_sync.c */
static gboolean pipe_data_available(int pipe_fd)
{
@ -896,6 +994,16 @@ void extcap_if_cleanup(capture_options *capture_opts, gchar **errormsg)
ws_unlink(interface_opts.extcap_fifo);
interface_opts.extcap_fifo = NULL;
}
if (interface_opts.extcap_control_in && file_exists(interface_opts.extcap_control_in))
{
ws_unlink(interface_opts.extcap_control_in);
interface_opts.extcap_control_in = NULL;
}
if (interface_opts.extcap_control_out && file_exists(interface_opts.extcap_control_out))
{
ws_unlink(interface_opts.extcap_control_out);
interface_opts.extcap_control_out = NULL;
}
#endif
/* Maybe the client closed and removed fifo, but ws should check if
* pid should be closed */
@ -1088,6 +1196,16 @@ GPtrArray *extcap_prepare_arguments(interface_options interface_opts)
}
add_arg(EXTCAP_ARGUMENT_RUN_PIPE);
add_arg(interface_opts.extcap_fifo);
if (interface_opts.extcap_control_in)
{
add_arg(EXTCAP_ARGUMENT_CONTROL_OUT);
add_arg(interface_opts.extcap_control_in);
}
if (interface_opts.extcap_control_out)
{
add_arg(EXTCAP_ARGUMENT_CONTROL_IN);
add_arg(interface_opts.extcap_control_out);
}
if (interface_opts.extcap_args == NULL || g_hash_table_size(interface_opts.extcap_args) == 0)
{
/* User did not perform interface configuration.
@ -1189,6 +1307,13 @@ extcap_init_interfaces(capture_options *capture_opts)
continue;
}
/* create control pipes if having toolbar */
if (extcap_has_toolbar(interface_opts.name))
{
extcap_create_pipe(&interface_opts.extcap_control_in);
extcap_create_pipe(&interface_opts.extcap_control_out);
}
/* create pipe for fifo */
if (!extcap_create_pipe(&interface_opts.extcap_fifo))
{
@ -1393,15 +1518,22 @@ static void remove_extcap_entry(gpointer entry, gpointer data _U_)
static gboolean cb_load_interfaces(extcap_callback_info_t cb_info)
{
GList * interfaces = NULL, * walker = NULL;
GList * interfaces = NULL, * control_items = NULL, * walker = NULL;
extcap_interface * int_iter = NULL;
extcap_info * element = NULL;
iface_toolbar * toolbar_entry = NULL;
gchar * toolname = g_path_get_basename(cb_info.extcap);
GList * interface_keys = g_hash_table_get_keys(_loaded_interfaces);
/* Load interfaces from utility */
interfaces = extcap_parse_interfaces(cb_info.output);
interfaces = extcap_parse_interfaces(cb_info.output, &control_items);
if (control_items)
{
toolbar_entry = g_new0(iface_toolbar, 1);
toolbar_entry->controls = control_items;
}
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Loading interface list for %s ", cb_info.extcap);
@ -1447,6 +1579,11 @@ static gboolean cb_load_interfaces(extcap_callback_info_t cb_info)
}
help = int_iter->help;
if (toolbar_entry)
{
toolbar_entry->menu_title = g_strdup(int_iter->display);
toolbar_entry->help = g_strdup(int_iter->help);
}
walker = g_list_next(walker);
continue;
@ -1476,11 +1613,26 @@ static gboolean cb_load_interfaces(extcap_callback_info_t cb_info)
element->interfaces = g_list_append(element->interfaces, int_iter);
g_hash_table_insert(_tool_for_ifname, g_strdup(int_iter->call), g_strdup(toolname));
if (toolbar_entry)
{
if (!toolbar_entry->menu_title)
{
toolbar_entry->menu_title = g_strdup(int_iter->display);
}
toolbar_entry->ifnames = g_list_append(toolbar_entry->ifnames, g_strdup(int_iter->call));
}
}
walker = g_list_next(walker);
}
if (toolbar_entry && toolbar_entry->menu_title)
{
iface_toolbar_add(toolbar_entry);
extcap_iface_toolbar_add(cb_info.extcap, toolbar_entry);
}
g_list_foreach(interfaces, remove_extcap_entry, NULL);
g_list_free(interfaces);
g_list_free(interface_keys);
@ -1499,6 +1651,21 @@ extcap_load_interface_list(void)
gchar *argv;
gchar *error;
if (_toolbars)
{
// Remove existing interface toolbars here instead of in extcap_clear_interfaces()
// to avoid flicker in shown toolbars when refreshing interfaces.
GList *toolbar_list = g_hash_table_get_values (_toolbars);
for (GList *walker = toolbar_list; walker; walker = walker->next)
{
iface_toolbar *toolbar = (iface_toolbar *) walker->data;
iface_toolbar_remove(toolbar->menu_title);
}
g_hash_table_remove_all(_toolbars);
} else {
_toolbars = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_toolbar);
}
if (_loaded_interfaces == NULL)
{
_loaded_interfaces = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, extcap_free_interface_info);

View File

@ -43,13 +43,15 @@
#define EXTCAP_PIPE_PREFIX "wireshark_extcap"
#define EXTCAP_ARGUMENT_CONFIG "--extcap-config"
#define EXTCAP_ARGUMENT_LIST_INTERFACES "--extcap-interfaces"
#define EXTCAP_ARGUMENT_LIST_INTERFACES "--extcap-interfaces"
#define EXTCAP_ARGUMENT_INTERFACE "--extcap-interface"
#define EXTCAP_ARGUMENT_LIST_DLTS "--extcap-dlts"
#define EXTCAP_ARGUMENT_RUN_CAPTURE "--capture"
#define EXTCAP_ARGUMENT_CAPTURE_FILTER "--extcap-capture-filter"
#define EXTCAP_ARGUMENT_RUN_PIPE "--fifo"
#define EXTCAP_ARGUMENT_CONTROL_IN "--extcap-control-in"
#define EXTCAP_ARGUMENT_CONTROL_OUT "--extcap-control-out"
typedef struct _extcap_info {
gchar * basename;
@ -117,6 +119,9 @@ extcap_free_if_configuration(GList *list, gboolean free_args);
gboolean
extcap_has_configuration(const char * ifname, gboolean is_required);
gboolean
extcap_has_toolbar(const char *ifname);
#ifdef WIN32
HANDLE
extcap_get_win32_handle();

View File

@ -28,6 +28,9 @@
#include <glib.h>
#include <string.h>
#include "ui/iface_toolbar.h"
#include "wsutil/strtoi.h"
#include "extcap.h"
#include "extcap_parser.h"
@ -120,7 +123,7 @@ static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
rs->sentence = NULL;
/* Regex for catching just the allowed values for sentences */
if ((regex = g_regex_new("^[\\t| ]*(arg|value|interface|extcap|dlt)(?=[\\t| ]+\\{)",
if ((regex = g_regex_new("^[\\t| ]*(arg|value|interface|extcap|dlt|control)(?=[\\t| ]+\\{)",
(GRegexCompileFlags) G_REGEX_CASELESS, (GRegexMatchFlags) 0, NULL)) != NULL) {
g_regex_match(regex, s, (GRegexMatchFlags) 0, &match_info);
@ -193,6 +196,10 @@ static extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
param_type = EXTCAP_PARAM_VERSION;
} else if (g_ascii_strcasecmp(arg, "help") == 0) {
param_type = EXTCAP_PARAM_HELP;
} else if (g_ascii_strcasecmp(arg, "control") == 0) {
param_type = EXTCAP_PARAM_CONTROL;
} else if (g_ascii_strcasecmp(arg, "role") == 0) {
param_type = EXTCAP_PARAM_ROLE;
} else {
param_type = EXTCAP_PARAM_UNKNOWN;
}
@ -269,6 +276,24 @@ void extcap_free_arg(extcap_arg *a) {
g_free(a);
}
void extcap_free_toolbar_value(iface_toolbar_value *v) {
if (v == NULL)
return;
g_free(v->value);
g_free(v->display);
}
void extcap_free_toolbar_control(iface_toolbar_control *c) {
if (c == NULL)
return;
g_free(c->display);
g_free(c->validation);
g_free(c->tooltip);
g_free(c->placeholder);
}
void extcap_free_arg_list(GList *a) {
g_list_foreach(a, (GFunc)extcap_free_arg, NULL);
g_list_free(a);
@ -280,6 +305,12 @@ static gint glist_find_numbered_arg(gconstpointer listelem, gconstpointer needle
return 1;
}
static gint glist_find_numbered_control(gconstpointer listelem, gconstpointer needle) {
if (((const iface_toolbar_control *) listelem)->num == *((const int *) needle))
return 0;
return 1;
}
static void extcap_free_tokenized_sentence(gpointer s, gpointer user_data _U_) {
extcap_token_sentence *t = (extcap_token_sentence *)s;
@ -604,7 +635,179 @@ static extcap_interface *extcap_parse_interface_sentence(extcap_token_sentence *
return ri;
}
GList *extcap_parse_interfaces(gchar *output) {
static iface_toolbar_control *extcap_parse_control_sentence(GList *control_items, extcap_token_sentence *s)
{
extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
gchar *param_value = NULL;
iface_toolbar_control *control = NULL;
iface_toolbar_value *value = NULL;
GList *entry = NULL;
guint32 num = 0;
if (s == NULL)
return NULL;
if (g_ascii_strcasecmp(s->sentence, "control") == 0) {
sent = EXTCAP_SENTENCE_CONTROL;
} else if (g_ascii_strcasecmp(s->sentence, "value") == 0) {
sent = EXTCAP_SENTENCE_VALUE;
}
if (sent == EXTCAP_SENTENCE_UNKNOWN)
return NULL;
if (sent == EXTCAP_SENTENCE_CONTROL) {
control = g_new0(iface_toolbar_control, 1);
control->ctrl_type = INTERFACE_TYPE_UNKNOWN;
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ARGNUM));
if (param_value == NULL) {
extcap_free_toolbar_control(control);
return NULL;
}
if (!ws_strtou32(param_value, NULL, &num)) {
extcap_free_toolbar_control(control);
return NULL;
}
control->num = (int)num;
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY));
if (param_value == NULL) {
extcap_free_toolbar_control(control);
return NULL;
}
control->display = g_strdup(param_value);
if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALIDATION)))
!= NULL) {
control->validation = g_strdup(param_value);
}
if ((param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_REQUIRED)))
!= NULL) {
control->is_required = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
}
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_TOOLTIP));
if (param_value != NULL) {
control->tooltip = g_strdup(param_value);
}
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_PLACEHOLDER));
if (param_value != NULL) {
control->placeholder = g_strdup(param_value);
}
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_TYPE));
if (param_value == NULL) {
extcap_free_toolbar_control(control);
return NULL;
}
extcap_arg_type arg_type = EXTCAP_ARG_UNKNOWN;
if (g_ascii_strcasecmp(param_value, "boolean") == 0) {
control->ctrl_type = INTERFACE_TYPE_BOOLEAN;
arg_type = EXTCAP_ARG_BOOLEAN;
} else if (g_ascii_strcasecmp(param_value, "button") == 0) {
control->ctrl_type = INTERFACE_TYPE_BUTTON;
} else if (g_ascii_strcasecmp(param_value, "selector") == 0) {
control->ctrl_type = INTERFACE_TYPE_SELECTOR;
} else if (g_ascii_strcasecmp(param_value, "string") == 0) {
control->ctrl_type = INTERFACE_TYPE_STRING;
arg_type = EXTCAP_ARG_STRING;
} else {
printf("invalid type %s in CONTROL sentence\n", param_value);
extcap_free_toolbar_control(control);
return NULL;
}
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_ROLE));
if (param_value != NULL) {
if (g_ascii_strcasecmp(param_value, "control") == 0) {
control->ctrl_role = INTERFACE_ROLE_CONTROL;
} else if (g_ascii_strcasecmp(param_value, "help") == 0) {
control->ctrl_role = INTERFACE_ROLE_HELP;
} else if (g_ascii_strcasecmp(param_value, "logger") == 0) {
control->ctrl_role = INTERFACE_ROLE_LOGGER;
} else if (g_ascii_strcasecmp(param_value, "reset") == 0) {
control->ctrl_role = INTERFACE_ROLE_RESET;
} else {
printf("invalid role %s in CONTROL sentence\n", param_value);
control->ctrl_role = INTERFACE_ROLE_UNKNOWN;
}
} else {
/* Default role */
control->ctrl_role = INTERFACE_ROLE_CONTROL;
}
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DEFAULT));
if (param_value != NULL) {
if (arg_type != EXTCAP_ARG_UNKNOWN) {
extcap_complex *complex = extcap_parse_complex(arg_type, param_value);
if (complex != NULL) {
if (arg_type == EXTCAP_ARG_BOOLEAN) {
control->default_value.boolean = extcap_complex_get_bool(complex);
} else if (arg_type == EXTCAP_ARG_STRING) {
control->default_value.string = g_strdup(complex->_val);
}
extcap_free_complex(complex);
} else {
printf("invalid default, couldn't parse %s\n", param_value);
}
}
}
} else if (sent == EXTCAP_SENTENCE_VALUE) {
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_CONTROL));
if (param_value == NULL) {
printf("no control in VALUE sentence\n");
return NULL;
}
if (!ws_strtou32(param_value, NULL, &num)) {
extcap_free_toolbar_control(control);
return NULL;
}
entry = g_list_find_custom(control_items, &num, glist_find_numbered_control);
if (entry == NULL) {
printf("couldn't find control %u in list for VALUE sentence\n", num);
return NULL;
}
value = g_new0(iface_toolbar_value, 1);
value->num = (int)num;
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_VALUE));
if (param_value == NULL) {
extcap_free_toolbar_value(value);
return NULL;
}
value->value = g_strdup(param_value);
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DISPLAY));
if (param_value == NULL) {
extcap_free_toolbar_value(value);
return NULL;
}
value->display = g_strdup(param_value);
param_value = (gchar *)g_hash_table_lookup(s->param_list, ENUM_KEY(EXTCAP_PARAM_DEFAULT));
if (param_value != NULL) {
value->is_default = g_regex_match_simple(EXTCAP_BOOLEAN_REGEX, param_value, G_REGEX_CASELESS, (GRegexMatchFlags)0);
}
control = (iface_toolbar_control *)entry->data;
control->values = g_list_append(control->values, value);
return NULL;
}
return control;
}
GList *extcap_parse_interfaces(gchar *output, GList **control_items) {
GList *result = NULL;
GList *tokens = NULL;
@ -613,6 +816,7 @@ GList *extcap_parse_interfaces(gchar *output) {
while (walker) {
extcap_interface *ri = NULL;
iface_toolbar_control *ti = NULL;
extcap_token_sentence *if_sentence = (extcap_token_sentence *) walker->data;
if (if_sentence) {
@ -622,6 +826,13 @@ GList *extcap_parse_interfaces(gchar *output) {
if ((ri = extcap_parse_interface_sentence(if_sentence))) {
result = g_list_append(result, ri);
}
} else if (control_items &&
((g_ascii_strcasecmp(if_sentence->sentence, "control") == 0) ||
(g_ascii_strcasecmp(if_sentence->sentence, "value") == 0)))
{
if ((ti = extcap_parse_control_sentence(*control_items, if_sentence))) {
*control_items = g_list_append(*control_items, ti);
}
}
}

View File

@ -34,7 +34,8 @@ typedef enum {
EXTCAP_SENTENCE_VALUE,
EXTCAP_SENTENCE_EXTCAP,
EXTCAP_SENTENCE_INTERFACE,
EXTCAP_SENTENCE_DLT
EXTCAP_SENTENCE_DLT,
EXTCAP_SENTENCE_CONTROL
} extcap_sentence_type;
typedef enum {
@ -78,7 +79,9 @@ typedef enum {
EXTCAP_PARAM_SAVE,
EXTCAP_PARAM_VALIDATION,
EXTCAP_PARAM_VERSION,
EXTCAP_PARAM_HELP
EXTCAP_PARAM_HELP,
EXTCAP_PARAM_CONTROL,
EXTCAP_PARAM_ROLE
} extcap_param_type;
#define ENUM_KEY(s) GUINT_TO_POINTER((guint)s)
@ -197,7 +200,7 @@ void extcap_free_arg_list(GList *a);
GList * extcap_parse_args(gchar *output);
/* Parse all sentences for interfaces */
GList * extcap_parse_interfaces(gchar *output);
GList * extcap_parse_interfaces(gchar *output, GList **control_items);
/* Parse all sentences for DLTs */
GList * extcap_parse_dlts(gchar *output);

View File

@ -58,6 +58,7 @@
#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */
#define SP_DROPS 'D' /* count of packets dropped in capture */
#define SP_SUCCESS 'S' /* success indication, no extra data */
#define SP_TOOLBAR_CTRL 'T' /* interface toolbar control packet */
/*
* Win32 only: Indications sent out on the signal pipe (from parent to child)
* (UNIX-like sends signals for this)

View File

@ -34,6 +34,7 @@ set(COMMON_UI_SRC
failure_message.c
filter_files.c
firewall_rules.c
iface_toolbar.c
iface_lists.c
io_graph_item.c
language.c

View File

@ -60,6 +60,7 @@ WIRESHARK_UI_SRC = \
failure_message.c \
filter_files.c \
firewall_rules.c \
iface_toolbar.c \
iface_lists.c \
io_graph_item.c \
language.c \
@ -109,6 +110,7 @@ WIRESHARK_UI_INCLUDES = \
help_url.h \
packet_list_utils.h \
firewall_rules.h \
iface_toolbar.h \
iface_lists.h \
io_graph_item.h \
language.h \

68
ui/iface_toolbar.c Normal file
View File

@ -0,0 +1,68 @@
/* iface_toolbar.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include "iface_toolbar.h"
static iface_toolbar_add_cb_t iface_toolbar_add_cb;
static iface_toolbar_remove_cb_t iface_toolbar_remove_cb;
void iface_toolbar_add(const iface_toolbar *toolbar)
{
if (iface_toolbar_add_cb) {
iface_toolbar_add_cb(toolbar);
}
}
void iface_toolbar_remove(const gchar *menu_title)
{
if (iface_toolbar_remove_cb) {
iface_toolbar_remove_cb(menu_title);
}
}
gboolean iface_toolbar_use(void)
{
return iface_toolbar_add_cb ? TRUE : FALSE;
}
void iface_toolbar_register_cb(iface_toolbar_add_cb_t add_cb, iface_toolbar_remove_cb_t remove_cb)
{
iface_toolbar_add_cb = add_cb;
iface_toolbar_remove_cb = remove_cb;
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

105
ui/iface_toolbar.h Normal file
View File

@ -0,0 +1,105 @@
/* iface_toolbar.h
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __IFACE_TOOLBAR_H__
#define __IFACE_TOOLBAR_H__
#include "config.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum {
INTERFACE_TYPE_UNKNOWN,
INTERFACE_TYPE_BOOLEAN,
INTERFACE_TYPE_BUTTON,
INTERFACE_TYPE_SELECTOR,
INTERFACE_TYPE_STRING
} iface_toolbar_ctrl_type;
typedef enum {
INTERFACE_ROLE_UNKNOWN,
INTERFACE_ROLE_CONTROL,
INTERFACE_ROLE_HELP,
INTERFACE_ROLE_LOGGER,
INTERFACE_ROLE_RESET
} iface_toolbar_ctrl_role;
typedef struct _iface_toolbar_value {
int num;
gchar *value;
gchar *display;
gboolean is_default;
} iface_toolbar_value;
typedef struct _iface_toolbar_control {
int num;
iface_toolbar_ctrl_type ctrl_type;
iface_toolbar_ctrl_role ctrl_role;
gchar *display;
gchar *validation;
gboolean is_required;
gchar *tooltip;
gchar *placeholder;
union {
gboolean boolean;
gchar *string;
} default_value;
GList *values;
} iface_toolbar_control;
typedef struct _iface_toolbar {
gchar *menu_title;
gchar *help;
GList *ifnames;
GList *controls;
} iface_toolbar;
typedef void (*iface_toolbar_add_cb_t)(const iface_toolbar *);
typedef void (*iface_toolbar_remove_cb_t)(const gchar *);
void iface_toolbar_add(const iface_toolbar *toolbar);
void iface_toolbar_remove(const gchar *menu_title);
gboolean iface_toolbar_use(void);
void iface_toolbar_register_cb(iface_toolbar_add_cb_t, iface_toolbar_remove_cb_t);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __IFACE_TOOLBAR_H__ */
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -87,6 +87,9 @@ set(WIRESHARK_QT_HEADERS
gsm_map_summary_dialog.h
iax2_analysis_dialog.h
import_text_dialog.h
interface_toolbar.h
interface_toolbar_reader.h
interface_toolbar_lineedit.h
interface_tree_model.h
interface_tree_cache_model.h
interface_sort_filter_model.h
@ -257,6 +260,9 @@ set(WIRESHARK_QT_SRC
geometry_state_dialog.cpp
iax2_analysis_dialog.cpp
import_text_dialog.cpp
interface_toolbar.cpp
interface_toolbar_reader.cpp
interface_toolbar_lineedit.cpp
interface_tree_model.cpp
interface_tree_cache_model.cpp
interface_sort_filter_model.cpp
@ -418,6 +424,7 @@ set(WIRESHARK_QT_UI
iax2_analysis_dialog.ui
import_text_dialog.ui
interface_frame.ui
interface_toolbar.ui
io_graph_dialog.ui
layout_preferences_frame.ui
lbm_lbtrm_transport_dialog.ui

View File

@ -70,6 +70,7 @@ NODIST_GENERATED_HEADER_FILES = \
ui_iax2_analysis_dialog.h \
ui_import_text_dialog.h \
ui_interface_frame.h \
ui_interface_toolbar.h \
ui_io_graph_dialog.h \
ui_layout_preferences_frame.h \
ui_lbm_lbtrm_transport_dialog.h \
@ -215,6 +216,9 @@ MOC_HDRS = \
iax2_analysis_dialog.h \
import_text_dialog.h \
interface_frame.h \
interface_toolbar.h \
interface_toolbar_lineedit.h \
interface_toolbar_reader.h \
interface_tree_model.h \
interface_tree_cache_model.h \
interface_sort_filter_model.h \
@ -340,6 +344,7 @@ UI_FILES = \
iax2_analysis_dialog.ui \
import_text_dialog.ui \
interface_frame.ui \
interface_toolbar.ui \
io_graph_dialog.ui \
layout_preferences_frame.ui \
lbm_lbtrm_transport_dialog.ui \
@ -499,6 +504,9 @@ WIRESHARK_QT_SRC = \
iax2_analysis_dialog.cpp \
import_text_dialog.cpp \
interface_frame.cpp \
interface_toolbar.cpp \
interface_toolbar_lineedit.cpp \
interface_toolbar_reader.cpp \
interface_tree_model.cpp \
interface_tree_cache_model.cpp \
interface_sort_filter_model.cpp \
@ -822,6 +830,8 @@ io_graph_dialog.$(OBJEXT): ui_io_graph_dialog.h
interface_frame.$(OBJEXT): ui_interface_frame.h
interface_toolbar.$(OBJEXT): ui_interface_toolbar.h
layout_preferences_frame.$(OBJEXT): ui_layout_preferences_frame.h
lbm_lbtrm_transport_dialog.$(OBJEXT): ui_lbm_lbtrm_transport_dialog.h

View File

@ -47,6 +47,7 @@ FunnelTextDialog::FunnelTextDialog(const QString &title) :
if (!title.isEmpty()) {
loadGeometry(0, 0, QString("Funnel %1").arg(title));
}
setWindowTitle(wsApp->windowTitleString(title));
funnel_text_window_.funnel_text_dialog = this;
@ -75,7 +76,6 @@ void FunnelTextDialog::reject()
struct _funnel_text_window_t *FunnelTextDialog::textWindowNew(const QString title)
{
FunnelTextDialog *ftd = new FunnelTextDialog(title);
ftd->setWindowTitle(wsApp->windowTitleString(title));
ftd->show();
return &ftd->funnel_text_window_;
}

895
ui/qt/interface_toolbar.cpp Normal file
View File

@ -0,0 +1,895 @@
/* interface_toolbar.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <errno.h>
#include "interface_toolbar.h"
#include "interface_toolbar_lineedit.h"
#include "simple_dialog.h"
#include "ui/main_statusbar.h"
#include <ui_interface_toolbar.h>
#include "sync_pipe.h"
#include "wsutil/file_util.h"
#include <QCheckBox>
#include <QComboBox>
#include <QDesktopServices>
#include <QLineEdit>
#include <QPushButton>
#include <QThread>
#include <QUrl>
static const char *interface_type_property = "control_type";
static const char *interface_role_property = "control_role";
// From interface control protocol.
enum InterfaceControlCommand {
commandControlInitialized = 0,
commandControlSet = 1,
commandControlAdd = 2,
commandControlRemove = 3,
commandControlEnable = 4,
commandControlDisable = 5,
commandStatusMessage = 6,
commandInformationMessage = 7,
commandWarningMessage = 8,
commandErrorMessage = 9,
};
// To do:
// - Move control pipe handling to extcap
InterfaceToolbar::InterfaceToolbar(QWidget *parent, const iface_toolbar *toolbar) :
QFrame(parent),
ui(new Ui::InterfaceToolbar),
help_link_(toolbar->help),
use_spacer_(true)
{
ui->setupUi(this);
// Fill inn interfaces list and initialize default interface values
ui->interfacesComboBox->blockSignals(true);
for (GList *walker = toolbar->ifnames; walker; walker = walker->next)
{
QString ifname((gchar *)walker->data);
ui->interfacesComboBox->addItem(ifname);
interface_[ifname].reader_thread = NULL;
interface_[ifname].out_fd = -1;
interface_[ifname].log_dialog = NULL;
}
ui->interfacesComboBox->blockSignals(false);
initializeControls(toolbar);
#ifdef Q_OS_MAC
foreach (QWidget *w, findChildren<QWidget *>())
{
w->setAttribute(Qt::WA_MacSmallSize, true);
}
#endif
if (!use_spacer_)
{
ui->horizontalSpacer->changeSize(0,0, QSizePolicy::Fixed, QSizePolicy::Fixed);
}
updateWidgets();
}
InterfaceToolbar::~InterfaceToolbar()
{
foreach (QString ifname, interface_.keys())
{
if (interface_[ifname].log_dialog)
{
interface_[ifname].log_dialog->close();
}
}
delete ui;
}
void InterfaceToolbar::initializeControls(const iface_toolbar *toolbar)
{
for (GList *walker = toolbar->controls; walker; walker = walker->next)
{
iface_toolbar_control *control = (iface_toolbar_control *)walker->data;
if (control_widget_.contains(control->num))
{
// Already have a widget with this number
continue;
}
QWidget *widget = NULL;
switch (control->ctrl_type)
{
case INTERFACE_TYPE_BOOLEAN:
widget = createCheckbox(control);
break;
case INTERFACE_TYPE_BUTTON:
widget = createButton(control);
break;
case INTERFACE_TYPE_SELECTOR:
widget = createSelector(control);
break;
case INTERFACE_TYPE_STRING:
widget = createString(control);
break;
default:
// Not supported
break;
}
if (widget)
{
widget->setProperty(interface_type_property, control->ctrl_type);
widget->setProperty(interface_role_property, control->ctrl_role);
control_widget_[control->num] = widget;
}
}
}
void InterfaceToolbar::setDefaultValue(int num, const QByteArray &value)
{
foreach (QString ifname, interface_.keys())
{
// Adding default value to all interfaces
interface_[ifname].value[num] = value;
}
default_value_[num] = value;
}
QWidget *InterfaceToolbar::createCheckbox(iface_toolbar_control *control)
{
QCheckBox *checkbox = new QCheckBox(QString().fromUtf8(control->display));
checkbox->setToolTip(QString().fromUtf8(control->tooltip));
if (control->default_value.boolean)
{
checkbox->setCheckState(Qt::Checked);
QByteArray default_value(1, 1);
setDefaultValue(control->num, default_value);
}
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(onCheckBoxChanged(int)));
ui->leftLayout->addWidget(checkbox);
return checkbox;
}
QWidget *InterfaceToolbar::createButton(iface_toolbar_control *control)
{
QPushButton *button = new QPushButton(QString().fromUtf8((gchar *)control->display));
button->setMaximumHeight(27);
button->setToolTip(QString().fromUtf8(control->tooltip));
switch (control->ctrl_role)
{
case INTERFACE_ROLE_CONTROL:
setDefaultValue(control->num, (gchar *)control->display);
connect(button, SIGNAL(pressed()), this, SLOT(onButtonPressed()));
break;
case INTERFACE_ROLE_HELP:
connect(button, SIGNAL(pressed()), this, SLOT(onHelpButtonPressed()));
if (help_link_.isEmpty())
{
// No help URL provided
button->hide();
}
break;
case INTERFACE_ROLE_LOGGER:
connect(button, SIGNAL(pressed()), this, SLOT(onLogButtonPressed()));
break;
case INTERFACE_ROLE_RESET:
button->setText("Reset");
button->setToolTip("Restore default values");
connect(button, SIGNAL(pressed()), this, SLOT(onResetButtonPressed()));
break;
default:
break;
}
ui->rightLayout->addWidget(button);
return button;
}
QWidget *InterfaceToolbar::createSelector(iface_toolbar_control *control)
{
QLabel *label = new QLabel(QString().fromUtf8(control->display));
label->setToolTip(QString().fromUtf8(control->tooltip));
QComboBox *combobox = new QComboBox();
combobox->setToolTip(QString().fromUtf8(control->tooltip));
combobox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
for (GList *walker = control->values; walker; walker = walker->next)
{
iface_toolbar_value *val = (iface_toolbar_value *)walker->data;
QString value = QString().fromUtf8((gchar *)val->value);
if (value.length() == 0)
{
// Invalid value
continue;
}
QString display = QString().fromUtf8((gchar *)val->display);
QByteArray interface_value;
interface_value.append(value);
if (display.length() == 0)
{
display = value;
}
else
{
interface_value.append('\0' + display);
}
combobox->addItem(display, value);
if (val->is_default)
{
combobox->setCurrentText(display);
setDefaultValue(control->num, value.toUtf8());
}
foreach (QString ifname, interface_.keys())
{
// Adding values to all interfaces
interface_[ifname].list[control->num].append(interface_value);
}
default_list_[control->num].append(interface_value);
}
connect(combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(onComboBoxChanged(int)));
ui->leftLayout->addWidget(label);
ui->leftLayout->addWidget(combobox);
label_widget_[control->num] = label;
return combobox;
}
QWidget *InterfaceToolbar::createString(iface_toolbar_control *control)
{
QLabel *label = new QLabel(QString().fromUtf8(control->display));
label->setToolTip(QString().fromUtf8(control->tooltip));
InterfaceToolbarLineEdit *lineedit = new InterfaceToolbarLineEdit(NULL, control->validation, control->is_required);
lineedit->setToolTip(QString().fromUtf8(control->tooltip));
lineedit->setPlaceholderText(QString().fromUtf8(control->placeholder));
if (control->default_value.string)
{
lineedit->setText(QString().fromUtf8(control->default_value.string));
setDefaultValue(control->num, control->default_value.string);
}
connect(lineedit, SIGNAL(editedTextApplied()), this, SLOT(onLineEditChanged()));
ui->leftLayout->addWidget(label);
ui->leftLayout->addWidget(lineedit);
label_widget_[control->num] = label;
use_spacer_ = false;
return lineedit;
}
void InterfaceToolbar::setWidgetValue(QWidget *widget, int command, QByteArray payload)
{
if (QComboBox *combobox = dynamic_cast<QComboBox *>(widget))
{
combobox->blockSignals(true);
switch (command)
{
case commandControlSet:
{
int idx = combobox->findData(payload);
if (idx != -1)
{
combobox->setCurrentIndex(idx);
}
break;
}
case commandControlAdd:
{
QString value;
QString display;
if (payload.contains('\0'))
{
// The payload contains "value\0display"
QList<QByteArray> values = payload.split('\0');
value = values[0];
display = values[1];
}
else
{
value = display = payload;
}
int idx = combobox->findData(value);
if (idx != -1)
{
// The value already exists, update item text
combobox->setItemText(idx, display);
}
else
{
combobox->addItem(display, value);
}
break;
}
case commandControlRemove:
{
if (payload.size() == 0)
{
combobox->clear();
}
else
{
int idx = combobox->findData(payload);
if (idx != -1)
{
combobox->removeItem(idx);
}
}
break;
}
default:
break;
}
combobox->blockSignals(false);
}
else if (InterfaceToolbarLineEdit *lineedit = dynamic_cast<InterfaceToolbarLineEdit *>(widget))
{
// We don't block signals here because changes are applied with enter or apply button,
// and we want InterfaceToolbarLineEdit to always syntax check the text.
switch (command)
{
case commandControlSet:
lineedit->setText(payload);
lineedit->disableApplyButton();
break;
default:
break;
}
}
else if (QCheckBox *checkbox = dynamic_cast<QCheckBox *>(widget))
{
checkbox->blockSignals(true);
switch (command)
{
case commandControlSet:
{
Qt::CheckState state = Qt::Unchecked;
if (payload.size() > 0 && payload.at(0) != 0)
{
state = Qt::Checked;
}
checkbox->setCheckState(state);
break;
}
default:
break;
}
checkbox->blockSignals(false);
}
else if (QPushButton *button = dynamic_cast<QPushButton *>(widget))
{
if ((command == commandControlSet) &&
widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
{
button->setText(payload);
}
}
}
void InterfaceToolbar::setInterfaceValue(QString ifname, QWidget *widget, int num, int command, QByteArray payload)
{
if (dynamic_cast<QComboBox *>(widget))
{
switch (command)
{
case commandControlSet:
foreach (QByteArray entry, interface_[ifname].list[num])
{
if (entry == payload || entry.startsWith(payload + '\0'))
{
interface_[ifname].value[num] = payload;
}
}
break;
case commandControlAdd:
interface_[ifname].list[num].append(payload);
break;
case commandControlRemove:
if (payload.size() == 0)
{
interface_[ifname].value[num].clear();
interface_[ifname].list[num].clear();
}
else
{
foreach (QByteArray entry, interface_[ifname].list[num])
{
if (entry == payload || entry.startsWith(payload + '\0'))
{
interface_[ifname].list[num].removeAll(entry);
}
}
}
break;
default:
break;
}
}
else if (dynamic_cast<InterfaceToolbarLineEdit *>(widget))
{
switch (command)
{
case commandControlSet:
interface_[ifname].value[num] = payload;
break;
default:
break;
}
}
else if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
(widget->property(interface_role_property).toInt() == INTERFACE_ROLE_LOGGER))
{
if (command == commandControlSet)
{
if (interface_[ifname].log_dialog)
{
interface_[ifname].log_dialog->clearText();
}
interface_[ifname].log_text.clear();
}
if (command == commandControlSet || command == commandControlAdd)
{
if (interface_[ifname].log_dialog)
{
interface_[ifname].log_dialog->appendText(payload);
}
interface_[ifname].log_text.append(payload);
}
}
else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
{
// QCheckBox or QPushButton
interface_[ifname].value[num] = payload;
}
}
void InterfaceToolbar::controlReceived(QString ifname, int num, int command, QByteArray payload)
{
switch (command)
{
case commandControlSet:
case commandControlAdd:
case commandControlRemove:
if (QWidget *widget = control_widget_[num])
{
setInterfaceValue(ifname, widget, num, command, payload);
if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
{
setWidgetValue(widget, command, payload);
}
}
break;
case commandControlEnable:
case commandControlDisable:
if (QWidget *widget = control_widget_[num])
{
if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
{
bool enable = (command == commandControlEnable ? true : false);
interface_[ifname].widget_disabled[num] = !enable;
if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
{
widget->setEnabled(enable);
if (label_widget_.contains(num))
{
label_widget_[num]->setEnabled(enable);
}
}
}
}
break;
case commandStatusMessage:
statusbar_push_temporary_msg("%s", payload.data());
break;
case commandInformationMessage:
simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, "%s", payload.data());
break;
case commandWarningMessage:
simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK, "%s", payload.data());
break;
case commandErrorMessage:
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", payload.data());
break;
default:
// Unknown commands are silently ignored
break;
}
}
void InterfaceToolbar::controlSend(QString ifname, int num, int command, const QByteArray &payload = QByteArray())
{
if (payload.length() > 65535)
{
// Not supported
return;
}
if (interface_[ifname].out_fd == -1)
{
// Does not have a control out channel
return;
}
ssize_t payload_length = payload.length() + 2;
unsigned char high_nibble = (payload_length >> 16) & 0xFF;
unsigned char mid_nibble = (payload_length >> 8) & 0xFF;
unsigned char low_nibble = (payload_length >> 0) & 0xFF;
QByteArray ba;
ba.append(SP_TOOLBAR_CTRL);
ba.append(high_nibble);
ba.append(mid_nibble);
ba.append(low_nibble);
ba.append(num);
ba.append(command);
ba.append(payload);
if (ws_write(interface_[ifname].out_fd, ba.data(), ba.length()) != ba.length())
{
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Unable to send control message:\n%s.",
g_strerror(errno));
}
}
void InterfaceToolbar::onButtonPressed()
{
const QString &ifname = ui->interfacesComboBox->currentText();
QPushButton *button = static_cast<QPushButton *>(sender());
int num = control_widget_.key(button);
controlSend(ifname, num, commandControlSet);
}
void InterfaceToolbar::onCheckBoxChanged(int state)
{
const QString &ifname = ui->interfacesComboBox->currentText();
QCheckBox *checkbox = static_cast<QCheckBox *>(sender());
int num = control_widget_.key(checkbox);
QByteArray payload(1, state == Qt::Unchecked ? 0 : 1);
controlSend(ifname, num, commandControlSet, payload);
interface_[ifname].value[num] = payload;
}
void InterfaceToolbar::onComboBoxChanged(int idx)
{
const QString &ifname = ui->interfacesComboBox->currentText();
QComboBox *combobox = static_cast<QComboBox *>(sender());
int num = control_widget_.key(combobox);
QString value = combobox->itemData(idx).toString();
QByteArray payload(value.toUtf8());
controlSend(ifname, num, commandControlSet, payload);
interface_[ifname].value[num] = payload;
}
void InterfaceToolbar::onLineEditChanged()
{
const QString &ifname = ui->interfacesComboBox->currentText();
InterfaceToolbarLineEdit *lineedit = static_cast<InterfaceToolbarLineEdit *>(sender());
int num = control_widget_.key(lineedit);
QByteArray payload(lineedit->text().toUtf8());
controlSend(ifname, num, commandControlSet, payload);
interface_[ifname].value[num] = payload;
}
void InterfaceToolbar::onLogButtonPressed()
{
const QString &ifname = ui->interfacesComboBox->currentText();
if (!interface_[ifname].log_dialog)
{
QPushButton *button = static_cast<QPushButton *>(sender());
interface_[ifname].log_dialog = new FunnelTextDialog(ifname + " " + button->text());
connect(interface_[ifname].log_dialog, SIGNAL(accepted()), this, SLOT(closeLog()));
connect(interface_[ifname].log_dialog, SIGNAL(rejected()), this, SLOT(closeLog()));
interface_[ifname].log_dialog->setText(interface_[ifname].log_text);
}
interface_[ifname].log_dialog->show();
interface_[ifname].log_dialog->raise();
interface_[ifname].log_dialog->activateWindow();
}
void InterfaceToolbar::onHelpButtonPressed()
{
QUrl help_url(help_link_);
if (help_url.scheme().compare("file") != 0) {
QDesktopServices::openUrl(help_url);
}
}
void InterfaceToolbar::closeLog()
{
FunnelTextDialog *log_dialog = static_cast<FunnelTextDialog *>(sender());
foreach (QString ifname, interface_.keys())
{
if (interface_[ifname].log_dialog == log_dialog)
{
interface_[ifname].log_dialog = NULL;
}
}
}
void InterfaceToolbar::startReaderThread(QString ifname, QString control_in)
{
QThread *thread = new QThread;
InterfaceToolbarReader *reader = new InterfaceToolbarReader(ifname, control_in);
reader->moveToThread(thread);
connect(thread, SIGNAL(started()), reader, SLOT(loop()));
connect(reader, SIGNAL(finished()), thread, SLOT(quit()));
connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), reader, SLOT(deleteLater()));
connect(reader, SIGNAL(received(QString, int, int, QByteArray)),
this, SLOT(controlReceived(QString, int, int, QByteArray)));
interface_[ifname].reader_thread = thread;
thread->start();
}
void InterfaceToolbar::startCapture(QString ifname, QString control_in, QString control_out)
{
if (!interface_.contains(ifname) || // This interface is not for us
interface_[ifname].out_fd != -1) // Already have control channels for this interface
{
return;
}
// The reader thread will open control in channel
startReaderThread(ifname, control_in);
// Open control out channel
interface_[ifname].out_fd = ws_open(control_out.toUtf8(), O_WRONLY | O_BINARY, 0);
sendChangedValues(ifname);
controlSend(ifname, 0, commandControlInitialized);
updateWidgets();
}
void InterfaceToolbar::stopCapture()
{
foreach (QString ifname, interface_.keys())
{
if (interface_[ifname].reader_thread)
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
interface_[ifname].reader_thread->requestInterruption();
#endif
interface_[ifname].reader_thread = NULL;
}
if (interface_[ifname].out_fd != -1)
{
ws_close (interface_[ifname].out_fd);
interface_[ifname].out_fd = -1;
}
foreach (int num, control_widget_.keys())
{
// Reset disabled property for all widgets
interface_[ifname].widget_disabled[num] = false;
QWidget *widget = control_widget_[num];
if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
(widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
{
// Reset default value for control buttons
interface_[ifname].value[num] = default_value_[num];
if (ifname.compare(ui->interfacesComboBox->currentText()) == 0)
{
setWidgetValue(widget, commandControlSet, default_value_[num]);
}
}
}
}
updateWidgets();
}
void InterfaceToolbar::sendChangedValues(QString ifname)
{
// Send all values which has changed
foreach (int num, control_widget_.keys())
{
QWidget *widget = control_widget_[num];
if ((interface_[ifname].value[num] != default_value_[num]) &&
(widget->property(interface_type_property).toInt() != INTERFACE_TYPE_BUTTON) &&
(widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
{
controlSend(ifname, num, commandControlSet, interface_[ifname].value[num]);
}
}
}
void InterfaceToolbar::onResetButtonPressed()
{
const QString &ifname = ui->interfacesComboBox->currentText();
// Set default values to all widgets and interfaces
foreach (int num, control_widget_.keys())
{
QWidget *widget = control_widget_[num];
if (default_list_[num].size() > 0)
{
// This is a QComboBox. Clear list and add new entries.
setWidgetValue(widget, commandControlRemove, QByteArray());
interface_[ifname].list[num].clear();
foreach (QByteArray value, default_list_[num])
{
setWidgetValue(widget, commandControlAdd, value);
interface_[ifname].list[num].append(value);
}
}
switch (widget->property(interface_role_property).toInt())
{
case INTERFACE_ROLE_CONTROL:
setWidgetValue(widget, commandControlSet, default_value_[num]);
interface_[ifname].value[num] = default_value_[num];
break;
case INTERFACE_ROLE_LOGGER:
if (interface_[ifname].log_dialog)
{
interface_[ifname].log_dialog->clearText();
}
interface_[ifname].log_text.clear();
break;
default:
break;
}
}
}
bool InterfaceToolbar::hasInterface(QString ifname)
{
return interface_.contains(ifname);
}
void InterfaceToolbar::updateWidgets()
{
const QString &ifname = ui->interfacesComboBox->currentText();
bool is_capturing = (interface_[ifname].out_fd == -1 ? false : true);
foreach (int num, control_widget_.keys())
{
QWidget *widget = control_widget_[num];
if (!is_capturing &&
(widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
(widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL))
{
widget->setEnabled(false);
}
else if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
{
bool widget_enabled = !interface_[ifname].widget_disabled[num];
widget->setEnabled(widget_enabled);
if (label_widget_.contains(num))
{
label_widget_[num]->setEnabled(widget_enabled);
}
}
}
foreach (int num, control_widget_.keys())
{
QWidget *widget = control_widget_[num];
if ((widget->property(interface_type_property).toInt() == INTERFACE_TYPE_BUTTON) &&
(widget->property(interface_role_property).toInt() == INTERFACE_ROLE_RESET))
{
widget->setEnabled(!is_capturing);
}
}
}
void InterfaceToolbar::on_interfacesComboBox_currentIndexChanged(const QString &ifname)
{
foreach (int num, control_widget_.keys())
{
QWidget *widget = control_widget_[num];
if (interface_[ifname].list[num].size() > 0)
{
// This is a QComboBox. Clear list and add new entries.
setWidgetValue(widget, commandControlRemove, QByteArray());
foreach (QByteArray value, interface_[ifname].list[num])
{
setWidgetValue(widget, commandControlAdd, value);
}
}
if (widget->property(interface_role_property).toInt() == INTERFACE_ROLE_CONTROL)
{
setWidgetValue(widget, commandControlSet, interface_[ifname].value[num]);
}
}
updateWidgets();
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

120
ui/qt/interface_toolbar.h Normal file
View File

@ -0,0 +1,120 @@
/* interface_toolbar.h
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INTERFACE_TOOLBAR_H
#define INTERFACE_TOOLBAR_H
#include <glib.h>
#include "ui/iface_toolbar.h"
#include "funnel_text_dialog.h"
#include "interface_toolbar_reader.h"
#include <QFrame>
#include <QMap>
#include <QString>
namespace Ui {
class InterfaceToolbar;
}
struct interface_values
{
QThread *reader_thread;
int out_fd;
QMap<int, QByteArray> value;
QMap<int, QList<QByteArray> > list;
FunnelTextDialog *log_dialog;
QString log_text;
QMap<int, bool> widget_disabled;
};
class InterfaceToolbar : public QFrame
{
Q_OBJECT
public:
explicit InterfaceToolbar(QWidget *parent = 0, const iface_toolbar *toolbar = NULL);
~InterfaceToolbar();
void startCapture(QString ifname, QString control_in, QString control_out);
void stopCapture();
bool hasInterface(QString ifname);
public slots:
void controlReceived(QString ifname, int num, int command, QByteArray message);
signals:
void closeReader();
private slots:
void startReaderThread(QString ifname, QString control_in);
void updateWidgets();
void onButtonPressed();
void onCheckBoxChanged(int state);
void onComboBoxChanged(int idx);
void onLineEditChanged();
void onLogButtonPressed();
void onHelpButtonPressed();
void onResetButtonPressed();
void closeLog();
void on_interfacesComboBox_currentIndexChanged(const QString &ifname);
private:
void initializeControls(const iface_toolbar *toolbar);
void setDefaultValue(int num, const QByteArray &value);
void sendChangedValues(QString ifname);
QWidget *createCheckbox(iface_toolbar_control *control);
QWidget *createButton(iface_toolbar_control *control);
QWidget *createSelector(iface_toolbar_control *control);
QWidget *createString(iface_toolbar_control *control);
void controlSend(QString ifname, int num, int type, const QByteArray &payload);
void setWidgetValue(QWidget *widget, int type, QByteArray payload);
void setInterfaceValue(QString ifname, QWidget *widget, int num, int type, QByteArray payload);
Ui::InterfaceToolbar *ui;
QMap<QString, struct interface_values> interface_;
QMap<int, QByteArray> default_value_;
QMap<int, QList<QByteArray> > default_list_;
QMap<int, QWidget *> control_widget_;
QMap<int, QWidget *> label_widget_;
QString help_link_;
bool use_spacer_;
};
#endif // INTERFACE_TOOLBAR_H
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>InterfaceToolbar</class>
<widget class="QFrame" name="InterfaceToolbar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>32</height>
</rect>
</property>
<property name="windowTitle">
<string>Frame</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="interfacesLabel">
<property name="toolTip">
<string>Select interface</string>
</property>
<property name="text">
<string>Interface</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="interfacesComboBox">
<property name="toolTip">
<string>Select interface</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="leftLayout"/>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="rightLayout"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,149 @@
/* interface_toolbar_lineedit.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "interface_toolbar_lineedit.h"
#include "stock_icon_tool_button.h"
#include "epan/prefs.h"
#include "color_utils.h"
#include <QStyle>
// To do:
// - Make a narrower apply button
InterfaceToolbarLineEdit::InterfaceToolbarLineEdit(QWidget *parent, QString validation_regex, bool is_required) :
QLineEdit(parent),
validation_regex_(validation_regex),
is_required_(is_required),
text_edited_(false)
{
apply_button_ = new StockIconToolButton(this, "x-filter-apply");
apply_button_->setCursor(Qt::ArrowCursor);
apply_button_->setEnabled(false);
apply_button_->setToolTip(tr("Apply changes"));
apply_button_->setIconSize(QSize(24, 14));
apply_button_->setStyleSheet(
"QToolButton {"
" border: none;"
" background: transparent;" // Disables platform style on Windows.
" padding: 0 0 0 0;"
"}"
);
updateStyleSheet(isValid());
connect(this, SIGNAL(textChanged(const QString &)), this, SLOT(validateText()));
connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(validateEditedText()));
connect(this, SIGNAL(returnPressed()), this, SLOT(applyEditedText()));
connect(apply_button_, SIGNAL(clicked()), this, SLOT(applyEditedText()));
}
void InterfaceToolbarLineEdit::validateText()
{
bool valid = isValid();
apply_button_->setEnabled(valid);
updateStyleSheet(valid);
}
void InterfaceToolbarLineEdit::validateEditedText()
{
text_edited_ = true;
}
void InterfaceToolbarLineEdit::applyEditedText()
{
if (text_edited_ && isValid())
{
emit editedTextApplied();
disableApplyButton();
}
}
void InterfaceToolbarLineEdit::disableApplyButton()
{
apply_button_->setEnabled(false);
text_edited_ = false;
}
bool InterfaceToolbarLineEdit::isValid()
{
bool valid = true;
if (is_required_ && text().length() == 0)
{
valid = false;
}
if (!validation_regex_.isEmpty() && text().length() > 0)
{
QRegExp expr(validation_regex_);
if (!expr.isValid() || expr.indexIn(text(), 0) == -1)
{
valid = false;
}
}
return valid;
}
void InterfaceToolbarLineEdit::updateStyleSheet(bool is_valid)
{
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
QSize apsz = apply_button_->sizeHint();
QString style_sheet = QString(
"InterfaceToolbarLineEdit {"
" padding-right: %1px;"
" background-color: %2;"
"}"
)
.arg(apsz.width() + frameWidth)
.arg(is_valid ? QString("") : ColorUtils::fromColorT(prefs.gui_text_invalid).name());
setStyleSheet(style_sheet);
}
void InterfaceToolbarLineEdit::resizeEvent(QResizeEvent *)
{
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
QSize apsz = apply_button_->sizeHint();
apply_button_->move(contentsRect().right() - frameWidth - apsz.width() + 2,
contentsRect().top());
apply_button_->setMinimumHeight(contentsRect().height());
apply_button_->setMaximumHeight(contentsRect().height());
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -0,0 +1,71 @@
/* interface_toolbar_lineedit.h
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INTERFACE_TOOLBAR_LINEEDIT_H
#define INTERFACE_TOOLBAR_LINEEDIT_H
#include <QLineEdit>
class StockIconToolButton;
class InterfaceToolbarLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit InterfaceToolbarLineEdit(QWidget *parent = 0, QString validation_regex = QString(), bool is_required = false);
void disableApplyButton();
protected:
void resizeEvent(QResizeEvent *);
signals:
void editedTextApplied();
private slots:
void validateText();
void validateEditedText();
void applyEditedText();
private:
bool isValid();
void updateStyleSheet(bool is_valid);
StockIconToolButton *apply_button_;
QString validation_regex_;
bool is_required_;
bool text_edited_;
};
#endif // INTERFACE_TOOLBAR_LINEEDIT_H
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -0,0 +1,140 @@
/* interface_toolbar_reader.cpp
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include "interface_toolbar_reader.h"
#include "sync_pipe.h"
#include "wsutil/file_util.h"
#include <QThread>
const int header_size = 6;
// To do:
// - Add support for WIN32
void InterfaceToolbarReader::loop()
{
#ifndef _WIN32
struct timeval timeout;
QByteArray header;
QByteArray payload;
fd_set readfds;
int fd = ws_open(control_in_.toUtf8(), O_RDONLY | O_BINARY | O_NONBLOCK, 0);
if (fd == -1)
{
emit finished();
return;
}
forever
{
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
int ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
if (ret == -1)
{
break;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
if (QThread::currentThread()->isInterruptionRequested())
{
break;
}
#endif
if (ret > 0 && FD_ISSET(fd, &readfds))
{
header.resize(header_size);
if (ws_read(fd, header.data(), header_size) != header_size)
{
break;
}
unsigned char high_nibble = header[1] & 0xFF;
unsigned char mid_nibble = header[2] & 0xFF;
unsigned char low_nibble = header[3] & 0xFF;
ssize_t payload_len = (ssize_t)((high_nibble << 16) + (mid_nibble << 8) + low_nibble) - 2;
payload.resize(payload_len);
if (payload_len > 0)
{
ssize_t total_len = 0;
while (total_len < payload_len)
{
ssize_t read_len = ws_read(fd, payload.data() + total_len, payload_len - total_len);
if (read_len == -1)
{
if (errno != EAGAIN)
{
break;
}
}
else
{
total_len += read_len;
}
}
if (total_len != payload_len)
{
break;
}
}
if (header[0] == SP_TOOLBAR_CTRL)
{
emit received(ifname_, (unsigned char)header[4], (unsigned char)header[5], payload);
}
}
}
ws_close(fd);
#endif
emit finished();
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -0,0 +1,65 @@
/* interface_toolbar_reader.h
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INTERFACE_TOOLBAR_READER_H
#define INTERFACE_TOOLBAR_READER_H
#include <QObject>
#include <QByteArray>
namespace Ui {
class InterfaceToolbarReader;
}
class InterfaceToolbarReader : public QObject
{
Q_OBJECT
public:
InterfaceToolbarReader(QString ifname, QString control_in, QObject *parent = 0) :
QObject(parent), ifname_(ifname), control_in_(control_in) {}
public slots:
void loop();
signals:
void received(QString ifname, int num, int command, QByteArray payload);
void finished();
private:
QString ifname_;
QString control_in_;
};
#endif // INTERFACE_TOOLBAR_READER_H
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/

View File

@ -33,6 +33,7 @@
#include <epan/export_object.h>
#include "ui/commandline.h"
#include "ui/iface_toolbar.h"
#ifdef HAVE_LIBPCAP
#include "ui/capture.h"
@ -61,6 +62,7 @@
#include "file_set_dialog.h"
#include "funnel_statistics.h"
#include "import_text_dialog.h"
#include "interface_toolbar.h"
#include "packet_list.h"
#include "proto_tree.h"
#include "simple_dialog.h"
@ -205,6 +207,23 @@ static void plugin_if_mainwindow_update_toolbars(gconstpointer user_data)
if (g_hash_table_lookup_extended(data_set, "toolbar_name", NULL, NULL)) {
QString toolbarName((const char *)g_hash_table_lookup(data_set, "toolbar_name"));
gbl_cur_main_window_->removeAdditionalToolbar(toolbarName);
}
}
static void mainwindow_add_toolbar(const iface_toolbar *toolbar_entry)
{
if (gbl_cur_main_window_ && toolbar_entry)
{
gbl_cur_main_window_->addInterfaceToolbar(toolbar_entry);
}
}
static void mainwindow_remove_toolbar(const gchar *menu_title)
{
if (gbl_cur_main_window_ && menu_title)
{
gbl_cur_main_window_->removeInterfaceToolbar(menu_title);
}
}
@ -759,6 +778,17 @@ MainWindow::MainWindow(QWidget *parent) :
#endif
plugin_if_register_gui_cb(PLUGIN_IF_REMOVE_TOOLBAR, plugin_if_mainwindow_update_toolbars);
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) && !defined(_WIN32)
// Register Interface Toolbar callbacks
//
// Qt version must be 5.2 or higher because the use of
// QThread::requestInterruption() in interface_toolbar.cpp and
// QThread::isInterruptionRequested() in interface_toolbar_reader.cpp
//
// The toolbar in/out control pipes are not supported on WIN32 yet.
iface_toolbar_register_cb(mainwindow_add_toolbar, mainwindow_remove_toolbar);
#endif
main_ui_->mainStack->setCurrentWidget(main_welcome_);
}
@ -779,6 +809,13 @@ QMenu *MainWindow::createPopupMenu()
menu->addAction(main_ui_->actionViewFilterToolbar);
menu->addAction(main_ui_->actionViewWirelessToolbar);
if (!main_ui_->menuInterfaceToolbars->actions().isEmpty()) {
QMenu *submenu = menu->addMenu(main_ui_->menuInterfaceToolbars->title());
foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
submenu->addAction(action);
}
}
if (!main_ui_->menuAdditionalToolbars->actions().isEmpty()) {
QMenu *subMenu = menu->addMenu(main_ui_->menuAdditionalToolbars->title());
foreach (QAction *action, main_ui_->menuAdditionalToolbars->actions()) {
@ -795,6 +832,76 @@ QMenu *MainWindow::createPopupMenu()
return menu;
}
void MainWindow::addInterfaceToolbar(const iface_toolbar *toolbar_entry)
{
QMenu *menu = main_ui_->menuInterfaceToolbars;
bool visible = g_list_find_custom(recent.interface_toolbars, toolbar_entry->menu_title, (GCompareFunc) strcmp) ? true : false;
QString title = QString().fromUtf8(toolbar_entry->menu_title);
QAction *action = new QAction(title, menu);
action->setEnabled(true);
action->setCheckable(true);
action->setChecked(visible);
action->setToolTip(tr("Show or hide the toolbar"));
QAction *before = NULL;
foreach (QAction *action, menu->actions()) {
// Ensure we add the menu entries in sorted order
if (action->text().compare(title, Qt::CaseInsensitive) > 0) {
before = action;
break;
}
}
menu->insertAction(before, action);
InterfaceToolbar *interface_toolbar = new InterfaceToolbar(this, toolbar_entry);
QToolBar *toolbar = new QToolBar(this);
toolbar->addWidget(interface_toolbar);
toolbar->setMovable(false);
toolbar->setVisible(visible);
action->setData(qVariantFromValue(toolbar));
addToolBar(Qt::TopToolBarArea, toolbar);
insertToolBarBreak(toolbar);
if (show_hide_actions_) {
show_hide_actions_->addAction(action);
}
menu->menuAction()->setVisible(true);
}
void MainWindow::removeInterfaceToolbar(const gchar *menu_title)
{
QMenu *menu = main_ui_->menuInterfaceToolbars;
QAction *action = NULL;
QMap<QAction *, QWidget *>::iterator i;
QString title = QString().fromUtf8(menu_title);
foreach (action, menu->actions()) {
if (title.compare(action->text()) == 0) {
break;
}
}
if (action) {
if (show_hide_actions_) {
show_hide_actions_->removeAction(action);
}
menu->removeAction(action);
QToolBar *toolbar = action->data().value<QToolBar *>();
removeToolBar(toolbar);
delete action;
delete toolbar;
}
menu->menuAction()->setVisible(!menu->actions().isEmpty());
}
void MainWindow::setPipeInputHandler(gint source, gpointer user_data, ws_process_id *child_process, pipe_input_cb_t input_cb)
{
pipe_source_ = source;
@ -1895,6 +2002,9 @@ void MainWindow::initShowHideMainWidgets()
showHideMainWidgets(shmwa);
}
// Initial hide the Interface Toolbar submenu
main_ui_->menuInterfaceToolbars->menuAction()->setVisible(false);
/* Initially hide the additional toolbars menus */
main_ui_->menuAdditionalToolbars->menuAction()->setVisible(false);
@ -2356,7 +2466,7 @@ void MainWindow::resizeEvent(QResizeEvent *event)
}
/* Update main window items based on whether there's a capture in progress. */
void MainWindow::setForCaptureInProgress(bool capture_in_progress)
void MainWindow::setForCaptureInProgress(bool capture_in_progress, GArray *ifaces)
{
setMenusForCaptureInProgress(capture_in_progress);
@ -2368,6 +2478,20 @@ void MainWindow::setForCaptureInProgress(bool capture_in_progress)
// set_capture_if_dialog_for_capture_in_progress(capture_in_progress);
#endif
#ifdef HAVE_EXTCAP
QList<InterfaceToolbar *> toolbars = findChildren<InterfaceToolbar *>();
foreach (InterfaceToolbar *toolbar, toolbars) {
if (capture_in_progress && ifaces) {
for (guint i = 0; i < ifaces->len; i++) {
interface_options interface_opts = g_array_index(ifaces, interface_options, i);
toolbar->startCapture(interface_opts.name, interface_opts.extcap_control_in, interface_opts.extcap_control_out);
}
} else {
toolbar->stopCapture();
}
}
#endif
}
static QList<register_stat_group_t> menu_groups = QList<register_stat_group_t>()

View File

@ -31,6 +31,7 @@
#include "file.h"
#include "ui/ui_util.h"
#include "ui/iface_toolbar.h"
#include <epan/prefs.h>
#include <epan/plugin_if.h>
@ -100,6 +101,9 @@ public:
void removeAdditionalToolbar(QString toolbarName);
void addInterfaceToolbar(const iface_toolbar *toolbar_entry);
void removeInterfaceToolbar(const gchar *menu_title);
protected:
virtual bool eventFilter(QObject *obj, QEvent *event);
virtual void keyPressEvent(QKeyEvent *event);
@ -224,7 +228,7 @@ private:
void externalMenuHelper(ext_menu_t * menu, QMenu * subMenu, gint depth);
void setForCaptureInProgress(bool capture_in_progress = false);
void setForCaptureInProgress(bool capture_in_progress = false, GArray *ifaces = NULL);
QMenu* findOrAddMenu(QMenu *parent_menu, QString& menu_text);
void recursiveCopyProtoTreeItems(QTreeWidgetItem *item, QString &clip, int ident_level);

View File

@ -268,6 +268,11 @@
<property name="title">
<string>&amp;View</string>
</property>
<widget class="QMenu" name="menuInterfaceToolbars">
<property name="title">
<string>Interface Toolbars</string>
</property>
</widget>
<widget class="QMenu" name="menuZoom">
<property name="title">
<string>&amp;Zoom</string>
@ -345,6 +350,7 @@
<addaction name="actionViewMainToolbar"/>
<addaction name="actionViewFilterToolbar"/>
<addaction name="actionViewWirelessToolbar"/>
<addaction name="menuInterfaceToolbars"/>
<addaction name="menuAdditionalToolbars" />
<addaction name="actionViewStatusBar"/>
<addaction name="separator"/>

View File

@ -119,6 +119,7 @@
#include "funnel_statistics.h"
#include "gsm_map_summary_dialog.h"
#include "iax2_analysis_dialog.h"
#include "interface_toolbar.h"
#include "io_graph_dialog.h"
#include <additional_toolbar.h>
#include "lbm_stream_dialog.h"
@ -486,6 +487,15 @@ void MainWindow::layoutToolbars()
main_ui_->wirelessToolBar->setVisible(recent.wireless_toolbar_show);
main_ui_->statusBar->setVisible(recent.statusbar_show);
foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
QToolBar *toolbar = action->data().value<QToolBar *>();
if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp)) {
toolbar->setVisible(true);
} else {
toolbar->setVisible(false);
}
}
QList<QToolBar *> toolbars = findChildren<QToolBar *>();
foreach (QToolBar *bar, toolbars) {
AdditionalToolBar *iftoolbar = dynamic_cast<AdditionalToolBar *>(bar);
@ -495,6 +505,7 @@ void MainWindow::layoutToolbars()
visible = true;
iftoolbar->setVisible(visible);
}
}
}
@ -523,6 +534,14 @@ void MainWindow::updateRecentActions()
main_ui_->actionViewPacketDetails->setChecked(recent.tree_view_show && prefs_has_layout_pane_content(layout_pane_content_pdetails));
main_ui_->actionViewPacketBytes->setChecked(recent.byte_view_show && prefs_has_layout_pane_content(layout_pane_content_pbytes));
foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
if (g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp)) {
action->setChecked(true);
} else {
action->setChecked(false);
}
}
foreach (QAction * action, main_ui_->menuAdditionalToolbars->actions()) {
ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
bool checked = false;
@ -628,7 +647,7 @@ void MainWindow::queuedFilterAction(QString action_filter, FilterAction::Action
// Capture callbacks
void MainWindow::captureCapturePrepared(capture_session *) {
void MainWindow::captureCapturePrepared(capture_session *session) {
#ifdef HAVE_LIBPCAP
setTitlebarForCaptureInProgress();
@ -636,7 +655,7 @@ void MainWindow::captureCapturePrepared(capture_session *) {
/* Disable menu items that make no sense if you're currently running
a capture. */
setForCaptureInProgress(true);
setForCaptureInProgress(true, session->capture_opts->ifaces);
// set_capture_if_dialog_for_capture_in_progress(TRUE);
// /* Don't set up main window for a capture file. */
@ -645,14 +664,14 @@ void MainWindow::captureCapturePrepared(capture_session *) {
#endif // HAVE_LIBPCAP
}
void MainWindow::captureCaptureUpdateStarted(capture_session *) {
void MainWindow::captureCaptureUpdateStarted(capture_session *session) {
#ifdef HAVE_LIBPCAP
/* We've done this in "prepared" above, but it will be cleared while
switching to the next multiple file. */
setTitlebarForCaptureInProgress();
setForCaptureInProgress(true);
setForCaptureInProgress(true, session->capture_opts->ifaces);
setForCapturedPackets(true);
#endif // HAVE_LIBPCAP
@ -2257,6 +2276,19 @@ void MainWindow::showHideMainWidgets(QAction *action)
recent.byte_view_show = show;
main_ui_->actionViewPacketBytes->setChecked(show);
} else {
foreach (QAction *action, main_ui_->menuInterfaceToolbars->actions()) {
QToolBar *toolbar = action->data().value<QToolBar *>();
if (widget == toolbar) {
GList *entry = g_list_find_custom(recent.interface_toolbars, action->text().toUtf8(), (GCompareFunc) strcmp);
if (show && !entry) {
recent.interface_toolbars = g_list_append(recent.interface_toolbars, g_strdup(action->text().toUtf8()));
} else if (!show && entry) {
recent.interface_toolbars = g_list_remove(recent.interface_toolbars, entry->data);
}
action->setChecked(show);
}
}
ext_toolbar_t * toolbar = VariantPointer<ext_toolbar_t>::asPtr(action->data());
if (toolbar) {
GList *entry = g_list_find_custom(recent.gui_additional_toolbars, toolbar->name, (GCompareFunc) strcmp);

View File

@ -75,6 +75,7 @@
#define RECENT_GUI_RLC_PDUS_FROM_MAC_FRAMES "gui.rlc_pdus_from_mac_frames"
#define RECENT_GUI_CUSTOM_COLORS "gui.custom_colors"
#define RECENT_GUI_TOOLBAR_SHOW "gui.additional_toolbar_show"
#define RECENT_GUI_INTERFACE_TOOLBAR_SHOW "gui.interface_toolbar_show"
#define RECENT_GUI_GEOMETRY "gui.geom."
@ -866,6 +867,12 @@ write_profile_recent(void)
fprintf(rf, RECENT_GUI_TOOLBAR_SHOW ": %s\n", string_list);
g_free(string_list);
fprintf(rf, "\n# Interface Toolbars show.\n");
fprintf(rf, "# List of interface toolbars to show.\n");
string_list = join_string_list(recent.interface_toolbars);
fprintf(rf, RECENT_GUI_INTERFACE_TOOLBAR_SHOW ": %s\n", string_list);
g_free(string_list);
fclose(rf);
/* XXX - catch I/O errors (e.g. "ran out of disk space") and return
@ -1121,6 +1128,8 @@ read_set_recent_pair_static(gchar *key, const gchar *value,
recent.gui_fileopen_remembered_dir = g_strdup(value);
} else if (strcmp(key, RECENT_GUI_TOOLBAR_SHOW) == 0) {
recent.gui_additional_toolbars = prefs_get_string_list(value);
} else if (strcmp(key, RECENT_GUI_INTERFACE_TOOLBAR_SHOW) == 0) {
recent.interface_toolbars = prefs_get_string_list(value);
}
return PREFS_SET_OK;
@ -1294,6 +1303,11 @@ recent_read_profile_static(char **rf_path_return, int *rf_errno_return)
recent.gui_additional_toolbars = NULL;
}
if (recent.interface_toolbars) {
g_list_free_full (recent.interface_toolbars, g_free);
recent.interface_toolbars = NULL;
}
/* Construct the pathname of the user's profile recent file. */
rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE);

View File

@ -111,6 +111,7 @@ typedef struct recent_settings_tag {
gboolean gui_rlc_use_pdus_from_mac;
GList *custom_colors;
GList *gui_additional_toolbars;
GList *interface_toolbars;
} recent_settings_t;
/** Global recent settings. */