Prefs/Extcap: Added support for password which is never stored on the disk

This commit is contained in:
j.novak@netsystem.cz 2021-12-30 16:03:15 +00:00 committed by Wireshark GitLab Utility
parent 6d0bd4e8e1
commit 6c9cb8f3fa
18 changed files with 198 additions and 25 deletions

View File

@ -1051,6 +1051,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
prefs_get_module_effect_flags@Base 2.5.0
prefs_get_max_value@Base 2.3.0
prefs_get_name@Base 2.3.0
prefs_get_password_value@Base 3.7.0
prefs_get_range_value@Base 2.3.0
prefs_get_range_value_real@Base 2.3.0
prefs_get_string_list@Base 1.9.1
@ -1083,6 +1084,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
prefs_register_filename_preference@Base 1.9.1
prefs_register_module_alias@Base 2.9.0
prefs_register_obsolete_preference@Base 1.9.1
prefs_register_password_preference@Base 3.7.0
prefs_register_protocol@Base 1.9.1
prefs_register_protocol_obsolete@Base 3.5.0
prefs_register_protocol_subtree@Base 1.9.1
@ -1104,6 +1106,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
prefs_set_enum_string_value@Base 3.5.0
prefs_set_gui_theme_is_dark@Base 2.5.0
prefs_set_module_effect_flags@Base 2.5.0
prefs_set_password_value@Base 3.7.0
prefs_set_pref@Base 1.9.1
prefs_set_preference_effect_fields@Base 3.3.0
prefs_set_range_value@Base 2.1.0

View File

@ -3055,6 +3055,11 @@ routines -
void prefs_register_string_preference(module_t *module, const char *name,
const char *title, const char *description, char **var)
/* Register a preference with a password (a character-string) value. */
/* The value is hold during runtime, only in memory. It is never written to disk */
void prefs_register_password_preference(module_t *module, const char *name,
const char *title, const char *description, char **var)
/* Register a preference with a file name (string) value.
* File name preferences are basically like string preferences
* except that the GUI gives the user the ability to browse for the

View File

@ -68,6 +68,10 @@ They previously shipped with Npcap 1.55.
* Capture Options dialog contains same configuration icon as Welcome Screen. It is possible to configure interface there.
* Extcap dialog remembers password items during runtime therefore it is possible to run extcap multiple times in row. Passwords are never stored to disk.
* It is possible to set extcap passwords on cli for tshark and other cli tools.
// === Removed Features and Support
// === Removed Dissectors

View File

@ -101,6 +101,7 @@ struct pref_custom_cbs {
#define PREF_DECODE_AS_UINT (1u << 12) /* XXX - These are only supported for "internal" (non-protocol) */
#define PREF_DECODE_AS_RANGE (1u << 13) /* use and not as a generic protocol preference */
#define PREF_OPEN_FILENAME (1u << 14)
#define PREF_PASSWORD (1u << 15) /* like string, but never saved to prefs file */
typedef enum {
GUI_ALL,
@ -249,6 +250,9 @@ WS_DLL_PUBLIC range_t* prefs_get_range_value_real(pref_t *pref, pref_source_t so
WS_DLL_PUBLIC gboolean prefs_add_decode_as_value(pref_t *pref, guint value, gboolean replace);
WS_DLL_PUBLIC gboolean prefs_remove_decode_as_value(pref_t *pref, guint value, gboolean set_default);
WS_DLL_PUBLIC unsigned int prefs_set_password_value(pref_t *pref, const char* value, pref_source_t source);
WS_DLL_PUBLIC char* prefs_get_password_value(pref_t *pref, pref_source_t source);
WS_DLL_PUBLIC void reset_pref(pref_t *pref);
/** read the preferences file (or similar) and call the callback

View File

@ -334,6 +334,7 @@ free_pref(gpointer data, gpointer user_data _U_)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
free_string_like_preference(pref);
break;
case PREF_RANGE:
@ -1906,6 +1907,21 @@ void prefs_register_decode_as_preference(module_t *module, const char *name,
preference->info.base = 10;
}
/*
* Register a preference with password value.
*/
void
prefs_register_password_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_PASSWORD, NULL, FALSE);
DIAG_ON(cast-qual)
}
gboolean prefs_add_decode_as_value(pref_t *pref, guint value, gboolean replace)
{
switch(pref->type)
@ -2026,6 +2042,7 @@ pref_stash(pref_t *pref, gpointer unused _U_)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
g_free(pref->stashed_val.string);
pref->stashed_val.string = g_strdup(*pref->varp.string);
break;
@ -2111,6 +2128,7 @@ pref_unstash(pref_t *pref, gpointer unstash_data_p)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
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);
@ -2217,6 +2235,7 @@ reset_stashed_pref(pref_t *pref) {
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
g_free(pref->stashed_val.string);
pref->stashed_val.string = g_strdup(pref->default_val.string);
break;
@ -2261,6 +2280,7 @@ pref_clean_stash(pref_t *pref, gpointer unused _U_)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
if (pref->stashed_val.string != NULL) {
g_free(pref->stashed_val.string);
pref->stashed_val.string = NULL;
@ -3743,7 +3763,7 @@ prefs_get_string_list(const gchar *str)
g_free(slstr);
break;
}
if (cur_c == '"' && ! backslash) {
if (cur_c == '"' && !backslash) {
switch (state) {
case PRE_STRING:
/* We hadn't yet started processing a string; this starts the
@ -3763,7 +3783,7 @@ prefs_get_string_list(const gchar *str)
default:
break;
}
} else if (cur_c == '\\' && ! backslash) {
} else if (cur_c == '\\' && !backslash) {
/* We saw a backslash, and the previous character wasn't a
backslash; escape the next character.
@ -3771,7 +3791,7 @@ prefs_get_string_list(const gchar *str)
backslash = TRUE;
if (state == PRE_STRING)
state = NOT_IN_QUOT;
} else if (cur_c == ',' && state != IN_QUOT && ! backslash) {
} else if (cur_c == ',' && state != IN_QUOT && !backslash) {
/* We saw a comma, and we're not in the middle of a quoted string
and it wasn't preceded by a backslash; it's the end of
the string we were working on... */
@ -3966,7 +3986,7 @@ parse_column_format(fmt_data *cfmt, const char *fmt)
strncmp(fmt, cust_format, cust_format_len) == 0) {
/* Yes. */
col_fmt = COL_CUSTOM;
cust_format_info = g_strsplit(&fmt[cust_format_len+1],":",3); /* add 1 for ':' */
cust_format_info = g_strsplit(&fmt[cust_format_len+1], ":", 3); /* add 1 for ':' */
col_custom_fields = g_strdup(cust_format_info[0]);
if (col_custom_fields && cust_format_info[1]) {
col_custom_occurrence = strtol(cust_format_info[1], &p, 10);
@ -4255,6 +4275,7 @@ reset_pref(pref_t *pref)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
reset_string_like_preference(pref);
break;
@ -4774,6 +4795,12 @@ guint prefs_get_uint_value(const char *module_name, const char* pref_name)
return prefs_get_uint_value_real(prefs_find_preference(prefs_find_module(module_name), pref_name), pref_current);
}
char* prefs_get_password_value(pref_t *pref, pref_source_t source)
{
return prefs_get_string_value(pref, source);
}
unsigned int prefs_set_uint_value(pref_t *pref, guint value, pref_source_t source)
{
unsigned int changed = 0;
@ -4805,6 +4832,16 @@ unsigned int prefs_set_uint_value(pref_t *pref, guint value, pref_source_t sourc
return changed;
}
/*
* For use by UI code that sets preferences.
*/
unsigned int
prefs_set_password_value(pref_t *pref, const char* value, pref_source_t source)
{
return prefs_set_string_value(pref, value, source);
}
guint prefs_get_uint_base(pref_t *pref)
{
return pref->info.base;
@ -5940,6 +5977,11 @@ set_pref(gchar *pref_name, const gchar *value, void *private_data _U_,
containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
break;
case PREF_PASSWORD:
/* Read value is everytime empty */
containing_module->prefs_changed_flags |= prefs_set_string_value(pref, "", pref_current);
break;
case PREF_RANGE:
{
if (!prefs_set_range_value_work(pref, value, return_range_errors,
@ -6124,6 +6166,10 @@ prefs_pref_type_name(pref_t *pref)
case PREF_UAT:
type_name = "UAT";
break;
case PREF_PASSWORD:
type_name = "Password";
break;
}
return type_name;
}
@ -6270,6 +6316,10 @@ prefs_pref_type_description(pref_t *pref)
type_desc = "Configuration data stored in its own file";
break;
case PREF_PASSWORD:
type_desc = "Password (never stored on disk)";
break;
default:
break;
}
@ -6315,6 +6365,7 @@ prefs_pref_is_default(pref_t *pref)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
return TRUE;
break;
@ -6469,6 +6520,9 @@ prefs_pref_to_str(pref_t *pref, pref_source_t source) {
break;
}
case PREF_PASSWORD:
return g_strdup(*(const char **) valp);
default:
break;
}
@ -6524,14 +6578,15 @@ write_pref(gpointer data, gpointer user_data)
char *type_desc, *pref_text;
const char * def_prefix = prefs_pref_is_default(pref) ? "#" : "";
if (pref->type == PREF_CUSTOM) fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
if (pref->type == PREF_CUSTOM)
fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
fprintf(arg->pf, "\n");
if (pref->description &&
(g_ascii_strncasecmp(pref->description,"", 2) != 0)) {
if (pref->type != PREF_CUSTOM) {
/* We get duplicate lines otherwise. */
desc_lines = g_strsplit(pref->description,"\n",0);
desc_lines = g_strsplit(pref->description, "\n", 0);
for (i = 0; desc_lines[i] != NULL; ++i) {
fprintf(arg->pf, "# %s\n", desc_lines[i]);
}
@ -6542,7 +6597,7 @@ write_pref(gpointer data, gpointer user_data)
}
type_desc = prefs_pref_type_description(pref);
desc_lines = g_strsplit(type_desc,"\n",0);
desc_lines = g_strsplit(type_desc, "\n", 0);
for (i = 0; desc_lines[i] != NULL; ++i) {
fprintf(arg->pf, "# %s\n", desc_lines[i]);
}
@ -6551,12 +6606,19 @@ write_pref(gpointer data, gpointer user_data)
pref_text = prefs_pref_to_str(pref, pref_current);
fprintf(arg->pf, "%s%s.%s: ", def_prefix, name_prefix, pref->name);
desc_lines = g_strsplit(pref_text,"\n",0);
for (i = 0; desc_lines[i] != NULL; ++i) {
fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
if (pref->type != PREF_PASSWORD)
{
desc_lines = g_strsplit(pref_text, "\n", 0);
for (i = 0; desc_lines[i] != NULL; ++i) {
fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
}
if (i == 0)
fprintf(arg->pf, "\n");
g_strfreev(desc_lines);
} else {
/* We never store password value */
fprintf(arg->pf, "\n");
}
if (i == 0) fprintf(arg->pf, "\n");
g_strfreev(desc_lines);
g_free(pref_text);
}

View File

@ -767,6 +767,25 @@ void prefs_register_decode_as_range_preference(module_t *module, const char *nam
void prefs_register_decode_as_preference(module_t *module, const char *name,
const char *title, const char *description, guint *var);
/**
* Register a preference with an password (password is never stored).
* @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 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 the title in the preferences dialog
* @param description the description included 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
*/
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 that used to be supported but no longer is.
*

View File

@ -883,8 +883,14 @@ static gboolean cb_preference(extcap_callback_info_t cb_info)
*arg->pref_valptr = arg->default_complex->_val;
}
prefs_register_string_preference(dev_module, pref_name_for_prefs,
if (arg->arg_type == EXTCAP_ARG_PASSWORD)
{
prefs_register_password_preference(dev_module, pref_name_for_prefs,
pref_title, pref_title, (const char **)arg->pref_valptr);
} else {
prefs_register_string_preference(dev_module, pref_name_for_prefs,
pref_title, pref_title, (const char **)arg->pref_valptr);
}
}
else
{

View File

@ -524,9 +524,8 @@ static extcap_arg *extcap_parse_arg_sentence(GList *args, extcap_token_sentence
} else if (g_ascii_strcasecmp(param_value, "string") == 0) {
target_arg->arg_type = EXTCAP_ARG_STRING;
} else if (g_ascii_strcasecmp(param_value, "password") == 0) {
/* Password is never saved because is mapped to PREF_PASSWORD later */
target_arg->arg_type = EXTCAP_ARG_PASSWORD;
/* default setting is to not save passwords */
target_arg->save = FALSE;
} else if (g_ascii_strcasecmp(param_value, "fileselect") == 0) {
target_arg->arg_type = EXTCAP_ARG_FILESELECT;
} else if (g_ascii_strcasecmp(param_value, "multicheck") == 0) {

View File

@ -4455,6 +4455,7 @@ sharkd_session_process_dumpconf_cb(pref_t *pref, gpointer d)
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
sharkd_json_value_string("s", prefs_get_string_value(pref, pref_current));
break;
@ -4558,7 +4559,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)
* (o) s - preference value (for PREF_STRING, PREF_SAVE_FILENAME, PREF_OPEN_FILENAME, PREF_DIRNAME, PREF_PASSWORD)
* (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

@ -299,6 +299,13 @@ my %APIs = (
my @apiGroups = qw(prohibited deprecated soft-deprecated);
# Defines array of pairs function/variable which are excluded
# from prefs_register_*_preference checks
my @excludePrefsCheck = (
[ qw(prefs_register_password_preference), '(const char **)arg->pref_valptr' ],
[ qw(prefs_register_string_preference), '(const char **)arg->pref_valptr' ],
);
# Given a ref to a hash containing "functions" and "functions_count" entries:
# Determine if any item of the list of APIs contained in the array referenced by "functions"
@ -869,6 +876,7 @@ sub check_pref_var_dupes($$)
my @dupes;
my %count;
while ($filecontents =~ /prefs_register_(\w+?)_preference/gs) {
my ($func) = "prefs_register_$1_preference";
my ($args) = extract_bracketed(substr($filecontents, $+[0]), '()');
$args = substr($args, 1, -1); # strip parens
@ -876,7 +884,17 @@ sub check_pref_var_dupes($$)
next if exists $prefs_register_var_pos{$1} and not defined $pos;
$pos //= -1;
my $var = (split /\s*,\s*(?![^(]*\))/, $args)[$pos]; # only commas outside parens
push @dupes, $var if $count{$var}++ == 1;
my $ignore = 0;
for my $row (@excludePrefsCheck) {
my ($rfunc, $rvar) = @$row;
if (($rfunc eq $func) && ($rvar eq $var)) {
$ignore = 1
}
}
if (!$ignore) {
push @dupes, $var if $count{$var}++ == 1;
}
}
if (@dupes) {

View File

@ -85,11 +85,11 @@ prefs_store_ext_helper(const char * module_name, const char *pref_name, const ch
pref_t * pref = NULL;
unsigned int pref_changed = 0;
if ( ! prefs_is_registered_protocol(module_name))
if ( !prefs_is_registered_protocol(module_name))
return 0;
module = prefs_find_module(module_name);
if ( ! module )
if ( !module )
return 0;
pref = prefs_find_preference(module, pref_name);
@ -100,8 +100,13 @@ prefs_store_ext_helper(const char * module_name, const char *pref_name, const ch
if (prefs_get_type(pref) == PREF_STRING )
{
pref_changed |= prefs_set_string_value(pref, pref_value, pref_stashed);
if ( ! pref_changed || prefs_get_string_value(pref, pref_stashed) != 0 )
if ( !pref_changed || prefs_get_string_value(pref, pref_stashed) != 0 )
pref_changed |= prefs_set_string_value(pref, pref_value, pref_current);
} else if (prefs_get_type(pref) == PREF_PASSWORD )
{
pref_changed |= prefs_set_password_value(pref, pref_value, pref_stashed);
if ( !pref_changed || prefs_get_password_value(pref, pref_stashed) != 0 )
pref_changed |= prefs_set_password_value(pref, pref_value, pref_current);
}
return pref_changed;
@ -128,11 +133,11 @@ prefs_store_ext_multiple(const char * module, GHashTable * pref_values)
gboolean pref_changed = FALSE;
GList * keys = NULL;
if ( ! prefs_is_registered_protocol(module))
if ( !prefs_is_registered_protocol(module))
return pref_changed;
keys = g_hash_table_get_keys(pref_values);
if ( ! keys )
if ( !keys )
return pref_changed;
for ( GList * key = keys; key != NULL; key = g_list_next(key) )

View File

@ -442,7 +442,7 @@ QWidget * ExtArgText::createEditor(QWidget * parent)
textBox->setPlaceholderText(QString().fromUtf8(_argument->placeholder));
if (_argument->arg_type == EXTCAP_ARG_PASSWORD)
textBox->setEchoMode(QLineEdit::Password);
textBox->setEchoMode(QLineEdit::PasswordEchoOnEdit);
connect(textBox , SIGNAL(textChanged(QString)), SLOT(onStringChanged(QString)));

View File

@ -81,6 +81,20 @@ public:
REGISTER_PREFERENCE_TYPE(PREF_STRING, StringPreference)
REGISTER_PREFERENCE_TYPE(PREF_CUSTOM, StringPreference)
class PasswordPreference : public StringPreference
{
public:
PasswordPreference(QObject * parent = Q_NULLPTR) : StringPreference(parent) {}
virtual QWidget * editor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index)
{
QLineEdit *le = static_cast<QLineEdit *>(StringPreference::editor(parent, option, index));
le->setEchoMode(QLineEdit::PasswordEchoOnEdit);
return le;
}
};
REGISTER_PREFERENCE_TYPE(PREF_PASSWORD, PasswordPreference)
class UIntPreference : public StringPreference
{
public:

View File

@ -20,6 +20,7 @@
#include <QFont>
#include <QColor>
#include <QRegularExpression>
#include <QApplication>
// XXX Should we move this to ui/preference_utils?
static GHashTable * pref_ptr_to_pref_ = NULL;
@ -341,7 +342,8 @@ QString PrefsModel::typeToString(int type)
AdvancedPrefsModel::AdvancedPrefsModel(QObject * parent)
: QSortFilterProxyModel(parent),
filter_()
filter_(),
passwordChar_(QApplication::style()->styleHint(QStyle::SH_LineEdit_PasswordCharacter))
{
}
@ -400,7 +402,12 @@ QVariant AdvancedPrefsModel::data(const QModelIndex &dataindex, int role) const
if (item->getPref() == NULL)
return QVariant();
return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colValue, modelIndex.parent()), role);
if (PREF_PASSWORD == item->getPrefType())
{
return QString(sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colValue, modelIndex.parent()), role).toString().size(), passwordChar_);
} else {
return sourceModel()->data(sourceModel()->index(modelIndex.row(), PrefsModel::colValue, modelIndex.parent()), role);
}
default:
break;
}
@ -497,6 +504,9 @@ bool AdvancedPrefsModel::setData(const QModelIndex &dataindex, const QVariant &v
case PREF_STRING:
prefs_set_string_value(item->getPref(), value.toString().toStdString().c_str(), pref_stashed);
break;
case PREF_PASSWORD:
prefs_set_password_value(item->getPref(), value.toString().toStdString().c_str(), pref_stashed);
break;
case PREF_DECODE_AS_RANGE:
case PREF_RANGE:
prefs_set_stashed_range_value(item->getPref(), value.toString().toUtf8().constData());

View File

@ -127,6 +127,7 @@ protected:
private:
QString filter_;
const QChar passwordChar_;
};
class ModulePrefsModel : public QSortFilterProxyModel

View File

@ -143,6 +143,22 @@ pref_show(pref_t *pref, gpointer layout_ptr)
vb->addLayout(hb);
break;
}
case PREF_PASSWORD:
{
QHBoxLayout *hb = new QHBoxLayout();
QLabel *label = new QLabel(prefs_get_title(pref));
label->setToolTip(tooltip);
hb->addWidget(label);
QLineEdit *string_le = new QLineEdit();
string_le->setToolTip(tooltip);
string_le->setProperty(pref_prop_, VariantPointer<pref_t>::asQVariant(pref));
string_le->setMinimumWidth(string_le->fontMetrics().height() * 20);
string_le->setEchoMode(QLineEdit::PasswordEchoOnEdit);
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:
{
@ -256,6 +272,7 @@ ModulePreferencesScrollArea::ModulePreferencesScrollArea(module_t *module, QWidg
case PREF_SAVE_FILENAME:
case PREF_OPEN_FILENAME:
case PREF_DIRNAME:
case PREF_PASSWORD:
connect(le, &QLineEdit::textEdited, this, &ModulePreferencesScrollArea::stringLineEditTextEdited);
break;
case PREF_RANGE:

View File

@ -98,6 +98,7 @@ void PreferenceEditorFrame::editPreference(preference *pref, pref_module *module
browse_button = true;
// Fallthrough
case PREF_STRING:
case PREF_PASSWORD:
connect(ui->preferenceLineEdit, &SyntaxLineEdit::textChanged,
this, &PreferenceEditorFrame::stringLineEditTextEdited);
show = true;
@ -225,6 +226,9 @@ void PreferenceEditorFrame::on_buttonBox_accepted()
case PREF_DIRNAME:
apply = prefs_set_string_value(pref_, new_str_.toStdString().c_str(), pref_stashed);
break;
case PREF_PASSWORD:
apply = prefs_set_password_value(pref_, new_str_.toStdString().c_str(), pref_stashed);
break;
case PREF_RANGE:
case PREF_DECODE_AS_RANGE:
apply = prefs_set_range_value(pref_, new_range_, pref_stashed);

View File

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