prefs: Add prefs_register_dissector_preference()

Use this preference to get color code validation and autocompletion
for string preferences used for configuring a dissector name.
This commit is contained in:
Stig Bjørlykke 2023-11-01 14:55:14 +01:00
parent 92546a4a66
commit 2f1392169a
15 changed files with 133 additions and 18 deletions

View File

@ -3268,6 +3268,10 @@ dissector_handle_get_protocol_index(const dissector_handle_t handle)
GList*
get_dissector_names(void)
{
if (!registered_dissectors) {
return NULL;
}
return g_hash_table_get_keys(registered_dissectors);
}

View File

@ -108,6 +108,8 @@ struct pref_custom_cbs {
*/
#define PREF_PROTO_TCP_SNDAMB_ENUM (1u << 16)
#define PREF_DISSECTOR (1u << 17) /* like string, but with dissector name syntax check */
/* read_prefs_file: read in a generic config file and do a callback to */
/* pref_set_pair_fct() for every key/value pair found */
/**

View File

@ -333,6 +333,7 @@ free_pref(gpointer data, gpointer user_data _U_)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
free_string_like_preference(pref);
break;
case PREF_RANGE:
@ -1969,6 +1970,19 @@ DIAG_OFF(cast-qual)
DIAG_ON(cast-qual)
}
/*
* Register a preference with a dissector name.
*/
void
prefs_register_dissector_preference(module_t *module, const char *name,
const char *title, const char *description,
const char **var)
{
DIAG_OFF(cast-qual)
register_string_like_preference(module, name, title, description,
(char **)var, PREF_DISSECTOR, NULL, FALSE);
DIAG_ON(cast-qual)
}
gboolean prefs_add_decode_as_value(pref_t *pref, guint value, gboolean replace)
{
@ -2091,6 +2105,7 @@ pref_stash(pref_t *pref, gpointer unused _U_)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
g_free(pref->stashed_val.string);
pref->stashed_val.string = g_strdup(*pref->varp.string);
break;
@ -2194,6 +2209,7 @@ pref_unstash(pref_t *pref, gpointer unstash_data_p)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0) {
unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
g_free(*pref->varp.string);
@ -2301,6 +2317,7 @@ reset_stashed_pref(pref_t *pref) {
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
g_free(pref->stashed_val.string);
pref->stashed_val.string = g_strdup(pref->default_val.string);
break;
@ -2353,6 +2370,7 @@ pref_clean_stash(pref_t *pref, gpointer unused _U_)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
if (pref->stashed_val.string != NULL) {
g_free(pref->stashed_val.string);
pref->stashed_val.string = NULL;
@ -4357,6 +4375,7 @@ reset_pref(pref_t *pref)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
reset_string_like_preference(pref);
break;
@ -6136,6 +6155,7 @@ set_pref(gchar *pref_name, const gchar *value, void *private_data _U_,
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_DISSECTOR:
containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
break;
@ -6339,6 +6359,10 @@ prefs_pref_type_name(pref_t *pref)
case PREF_PASSWORD:
type_name = "Password";
break;
case PREF_DISSECTOR:
type_name = "Dissector";
break;
}
return type_name;
}
@ -6490,6 +6514,10 @@ prefs_pref_type_description(pref_t *pref)
type_desc = "Password (never stored on disk)";
break;
case PREF_DISSECTOR:
type_desc = "A dissector name";
break;
default:
break;
}
@ -6537,6 +6565,7 @@ prefs_pref_is_default(pref_t *pref)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
return TRUE;
break;
@ -6656,6 +6685,8 @@ prefs_pref_to_str(pref_t *pref, pref_source_t source) {
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
return g_strdup(*(const char **) valp);
case PREF_DECODE_AS_RANGE:
@ -6692,9 +6723,6 @@ prefs_pref_to_str(pref_t *pref, pref_source_t source) {
break;
}
case PREF_PASSWORD:
return g_strdup(*(const char **) valp);
default:
break;
}

View File

@ -762,6 +762,30 @@ void prefs_register_decode_as_range_preference(module_t *module, const char *nam
WS_DLL_PUBLIC void prefs_register_password_preference(module_t *module, const char *name,
const char *title, const char *description, const char **var);
/**
* Register a preference with a dissector name.
* @param module the preferences module returned by prefs_register_protocol() or
* prefs_register_protocol_subtree()
* @param name the preference's identifier. This is appended to the name of the
* protocol, with a "." between them, to create a unique identifier.
* The identifier should not include the protocol name, as the name in
* the preference file will already have it. Make sure that
* only lower-case ASCII letters, numbers, underscores and
* dots appear in the preference name.
* @param title Field's title in the preferences dialog
* @param description description to include in the preferences file
* and shown as tooltip in the GUI, or NULL
* @param var pointer to the storage location that is updated when the
* field is changed in the preference dialog box. Note that
* with string preferences the given pointer is overwritten
* with a pointer to a new copy of the string during the
* preference registration. The passed-in string may be
* freed, but you must keep another pointer to the string
* in order to free it
*/
WS_DLL_PUBLIC void prefs_register_dissector_preference(module_t *module, const char *name,
const char *title, const char *description, const char **var);
/**
* Register a preference that used to be supported but no longer is.
*

View File

@ -180,6 +180,7 @@ WSLUA_FUNCTION wslua_get_preference(lua_State *L) {
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_DISSECTOR:
{
const gchar *string_value = prefs_get_string_value(pref, pref_current);
lua_pushstring(L,string_value);
@ -256,6 +257,7 @@ WSLUA_FUNCTION wslua_set_preference(lua_State *L) {
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_DISSECTOR:
{
const gchar *string_value = luaL_checkstring(L,WSLUA_ARG_set_preference_VALUE);
changed = prefs_set_string_value(pref, string_value, pref_current);

View File

@ -5190,6 +5190,7 @@ sharkd_session_process_dumpconf_cb(pref_t *pref, gpointer d)
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
sharkd_json_value_string("s", prefs_get_string_value(pref, pref_current));
break;
@ -5293,7 +5294,7 @@ sharkd_session_process_dumpconf_mod_cb(module_t *module, gpointer d)
* (o) u - preference value (for PREF_UINT, PREF_DECODE_AS_UINT)
* (o) ub - preference value suggested base for display (for PREF_UINT, PREF_DECODE_AS_UINT) and if different than 10
* (o) b - preference value (only for PREF_BOOL) (1 true, 0 false)
* (o) s - preference value (for PREF_STRING, PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME, PREF_PASSWORD)
* (o) s - preference value (for PREF_STRING, PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME, PREF_PASSWORD, PREF_DISSECTOR)
* (o) e - preference possible values (only for PREF_ENUM)
* (o) r - preference value (for PREF_RANGE, PREF_DECODE_AS_RANGE)
* (o) t - preference value (only for PREF_UAT)

View File

@ -93,7 +93,7 @@ prefs_store_ext_helper(const char * module_name, const char *pref_name, const ch
if (!pref)
return 0;
if (prefs_get_type(pref) == PREF_STRING )
if (prefs_get_type(pref) == PREF_STRING || prefs_get_type(pref) == PREF_DISSECTOR)
{
pref_changed |= prefs_set_string_value(pref, pref_value, pref_stashed);
if ( !pref_changed || prefs_get_string_value(pref, pref_stashed) != 0 )

View File

@ -80,6 +80,7 @@ public:
};
REGISTER_PREFERENCE_TYPE(PREF_STRING, StringPreference)
REGISTER_PREFERENCE_TYPE(PREF_CUSTOM, StringPreference)
REGISTER_PREFERENCE_TYPE(PREF_DISSECTOR, StringPreference)
class PasswordPreference : public StringPreference
{

View File

@ -487,6 +487,7 @@ bool AdvancedPrefsModel::setData(const QModelIndex &dataindex, const QVariant &v
prefs_set_enum_value(item->getPref(), value.toInt(), pref_stashed);
break;
case PREF_STRING:
case PREF_DISSECTOR:
prefs_set_string_value(item->getPref(), value.toString().toStdString().c_str(), pref_stashed);
break;
case PREF_PASSWORD:

View File

@ -10,6 +10,7 @@
#include "module_preferences_scroll_area.h"
#include <ui_module_preferences_scroll_area.h>
#include <ui/qt/widgets/syntax_line_edit.h>
#include <ui/qt/widgets/dissector_syntax_line_edit.h>
#include "ui/qt/widgets/wireshark_file_dialog.h"
#include <ui/qt/utils/qt_ui_utils.h>
#include "uat_dialog.h"
@ -171,6 +172,21 @@ pref_show(pref_t *pref, gpointer user_data)
vb->addLayout(hb);
break;
}
case PREF_DISSECTOR:
{
QHBoxLayout *hb = new QHBoxLayout();
QLabel *label = new QLabel(prefs_get_title(pref));
label->setToolTip(tooltip);
hb->addWidget(label);
QLineEdit *string_le = new DissectorSyntaxLineEdit();
string_le->setToolTip(tooltip);
string_le->setProperty(pref_prop_, VariantPointer<pref_t>::asQVariant(pref));
string_le->setMinimumWidth(string_le->fontMetrics().height() * 20);
hb->addWidget(string_le);
hb->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
vb->addLayout(hb);
break;
}
case PREF_DECODE_AS_RANGE:
case PREF_RANGE:
{
@ -333,6 +349,7 @@ ModulePreferencesScrollArea::ModulePreferencesScrollArea(module_t *module, QWidg
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
case PREF_DISSECTOR:
connect(le, &QLineEdit::textEdited, this, &ModulePreferencesScrollArea::stringLineEditTextEdited);
break;
case PREF_RANGE:

View File

@ -80,7 +80,14 @@ void PreferenceEditorFrame::editPreference(preference *pref, pref_module *module
ui->preferenceLineEdit->clear();
ui->preferenceLineEdit->setSyntaxState(SyntaxLineEdit::Empty);
disconnect(ui->preferenceLineEdit, 0, 0, 0);
// Disconnect previous textChanged signals.
disconnect(ui->preferenceLineEdit, &SyntaxLineEdit::textChanged,
this, &PreferenceEditorFrame::uintLineEditTextEdited);
disconnect(ui->preferenceLineEdit, &SyntaxLineEdit::textChanged,
this, &PreferenceEditorFrame::stringLineEditTextEdited);
disconnect(ui->preferenceLineEdit, &SyntaxLineEdit::textChanged,
this, &PreferenceEditorFrame::rangeLineEditTextEdited);
bool show = false;
bool browse_button = false;
@ -99,6 +106,7 @@ void PreferenceEditorFrame::editPreference(preference *pref, pref_module *module
// Fallthrough
case PREF_STRING:
case PREF_PASSWORD:
case PREF_DISSECTOR:
connect(ui->preferenceLineEdit, &SyntaxLineEdit::textChanged,
this, &PreferenceEditorFrame::stringLineEditTextEdited);
show = true;
@ -114,6 +122,16 @@ void PreferenceEditorFrame::editPreference(preference *pref, pref_module *module
}
if (show) {
// Enable completion only for display filter search.
if (prefs_get_type(pref_) == PREF_DISSECTOR) {
ui->preferenceLineEdit->allowCompletion(true);
ui->preferenceLineEdit->updateDissectorNames();
ui->preferenceLineEdit->setDefaultPlaceholderText();
} else {
ui->preferenceLineEdit->allowCompletion(false);
ui->preferenceLineEdit->setPlaceholderText("");
}
ui->preferenceLineEdit->setText(gchar_free_to_qstring(prefs_pref_to_str(pref_, pref_stashed)).remove(QRegularExpression("\n\t")));
ui->preferenceBrowseButton->setHidden(!browse_button);
animatedShow();
@ -143,8 +161,15 @@ void PreferenceEditorFrame::uintLineEditTextEdited(const QString &new_str)
void PreferenceEditorFrame::stringLineEditTextEdited(const QString &new_str)
{
bool ok = true;
new_str_ = new_str;
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
if (prefs_get_type(pref_) == PREF_DISSECTOR) {
ui->preferenceLineEdit->checkDissectorName(new_str_);
ok = (ui->preferenceLineEdit->syntaxState() != SyntaxLineEdit::Invalid);
}
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
}
void PreferenceEditorFrame::browsePushButtonClicked()
@ -227,6 +252,7 @@ void PreferenceEditorFrame::on_buttonBox_accepted()
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_DISSECTOR:
apply = prefs_set_string_value(pref_, new_str_.toStdString().c_str(), pref_stashed);
break;
case PREF_PASSWORD:
@ -280,7 +306,7 @@ void PreferenceEditorFrame::on_buttonBox_rejected()
void PreferenceEditorFrame::keyPressEvent(QKeyEvent *event)
{
if (event->modifiers() == Qt::NoModifier) {
if (pref_ && module_ && (event->modifiers() == Qt::NoModifier)) {
if (event->key() == Qt::Key_Escape) {
on_buttonBox_rejected();
} else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {

View File

@ -54,7 +54,7 @@
</widget>
</item>
<item>
<widget class="SyntaxLineEdit" name="preferenceLineEdit">
<widget class="DissectorSyntaxLineEdit" name="preferenceLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
@ -106,9 +106,9 @@
<container>1</container>
</customwidget>
<customwidget>
<class>SyntaxLineEdit</class>
<extends>QLineEdit</extends>
<header>widgets/syntax_line_edit.h</header>
<class>DissectorSyntaxLineEdit</class>
<extends>SyntaxLineEdit</extends>
<header>widgets/dissector_syntax_line_edit.h</header>
</customwidget>
</customwidgets>
<resources/>

View File

@ -270,6 +270,7 @@ void ProtocolPreferencesMenu::addMenuItem(preference *pref)
case PREF_DECODE_AS_UINT:
case PREF_DECODE_AS_RANGE:
case PREF_PASSWORD:
case PREF_DISSECTOR:
{
EditorPreferenceAction *epa = new EditorPreferenceAction(pref, this);
addAction(epa);

View File

@ -38,6 +38,15 @@ DissectorSyntaxLineEdit::DissectorSyntaxLineEdit(QWidget *parent) :
setCompleter(new QCompleter(completion_model_, this));
setCompletionTokenChars(fld_abbrev_chars_);
updateDissectorNames();
setDefaultPlaceholderText();
connect(this, &DissectorSyntaxLineEdit::textChanged, this,
static_cast<void (DissectorSyntaxLineEdit::*)(const QString &)>(&DissectorSyntaxLineEdit::checkDissectorName));
}
void DissectorSyntaxLineEdit::updateDissectorNames()
{
GList *dissector_names = get_dissector_names();
QStringList dissector_list;
for (GList* l = dissector_names; l != NULL; l = l->next) {
@ -46,10 +55,6 @@ DissectorSyntaxLineEdit::DissectorSyntaxLineEdit(QWidget *parent) :
g_list_free(dissector_names);
dissector_list.sort();
completion_model_->setStringList(dissector_list);
setDefaultPlaceholderText();
connect(this, &DissectorSyntaxLineEdit::textChanged, this,
static_cast<void (DissectorSyntaxLineEdit::*)(const QString &)>(&DissectorSyntaxLineEdit::checkDissectorName));
}
void DissectorSyntaxLineEdit::setDefaultPlaceholderText()

View File

@ -20,19 +20,22 @@ class DissectorSyntaxLineEdit : public SyntaxLineEdit
Q_OBJECT
public:
explicit DissectorSyntaxLineEdit(QWidget *parent = 0);
void updateDissectorNames();
void setDefaultPlaceholderText();
protected:
void keyPressEvent(QKeyEvent *event) { completionKeyPressEvent(event); }
void focusInEvent(QFocusEvent *event) { completionFocusInEvent(event); }
private slots:
public slots:
void checkDissectorName(const QString &dissector);
private slots:
void changeEvent(QEvent* event);
private:
QString placeholder_text_;
void setDefaultPlaceholderText();
void buildCompletionList(const QString &field_word, const QString &preamble);
};