Here's a patch to use pwmd for form history. pwmd is a daemon that listens on a local socket and waits for commands from clients to manipulate data. The data is an encrypted XML file. The password to open/save the file is gotten with gpg-agent. Read src/formhist/README.pwmd for more info.
-- Benjamin J. Kibbey [EMAIL PROTECTED]/jabber/freenode 3019 F5FC AA33 5BC7 BE9F 09D2 393E DBD2 40D5 FA7E
commit df755b42e5d58413a43c8243e68fbdc9b6842824
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sun Jan 28 08:28:14 2007 -0500
Only #include what is needed in pwmd.[ch].
elinks-git-18771fd+libpwmd-2.0.x-3.diff
commit 131a990d372ddf25a4a6103440cd5a6c05eab390
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sun Jan 28 08:16:30 2007 -0500
Include pwmd.h where needed to silence prototype warnings.
A couple more variable renamings to avoid confusion with libpwmd
names.
Cleaner 'struct string' usage.
Fixed a couple memory leaks from pwmd_command().
commit 74369b109e3ab3257e45a19012bd88002a0ce37f
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sun Jan 28 05:13:05 2007 -0500
Don't abort configure if libpwmd is not found or if formhist was
disabled. Also use pkg-config to configure libpwmd.
commit 3589f40931ce0954894adf298708e8952b00795a
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sat Jan 27 20:54:06 2007 -0500
Use N_() to set internationalization strings.
commit 04601083f58d4b5abfe423406e0e6ddcf01fa534
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sat Jan 27 20:41:24 2007 -0500
Don't do save_pwmd_formhist() in "anonymous" mode.
commit daaa0835464cb41cc444c9e26de1099e0fcf1823
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sat Jan 27 20:32:40 2007 -0500
Renamed some functions to be less confusing with libpwmd function
names.
commit 29a4b2606577f61fb4c3e8be061c2b586c6d5040
Author: Ben Kibbey <[EMAIL PROTECTED]>
Date: Sat Jan 27 20:23:00 2007 -0500
Better configuration option description strings.
diff --git a/Makefile.config.in b/Makefile.config.in
index 98afd5b..d7ff8ec 100644
--- a/Makefile.config.in
+++ b/Makefile.config.in
@@ -132,6 +132,7 @@ CONFIG_INTERLINK = @CONFIG_INTERLINK@
CONFIG_IPV6 = @CONFIG_IPV6@
CONFIG_JW = @CONFIG_JW@
CONFIG_LEDS = @CONFIG_LEDS@
+CONFIG_PWMD = @CONFIG_PWMD@
CONFIG_LZMA = @CONFIG_LZMA@
CONFIG_MAILCAP = @CONFIG_MAILCAP@
CONFIG_MANUAL = @CONFIG_MANUAL@
diff --git a/configure.in b/configure.in
index 4ee940a..920f858 100644
--- a/configure.in
+++ b/configure.in
@@ -483,6 +483,7 @@ EL_ARG_ENABLE(CONFIG_LZMA, lzma, [lzma],
[ --enable-lzma enable lzma encoding support])
dnl ===================================================================
+
dnl Check for GSSAPI, optional even if installed.
dnl ===================================================================
@@ -1192,6 +1193,37 @@ EL_ARG_ENABLE(CONFIG_COOKIES, cookies, [Cookies],
EL_ARG_ENABLE(CONFIG_FORMHIST, formhist, [Form history],
[ --disable-formhist disable form history support])
+
+CONFIG_PWMD=no
+AC_ARG_ENABLE(pwmd,
+ [ --enable-pwmd enable Password Manager Daemon support],
+ [if test "$enableval" != no; then enableval="yes"; fi
+ CONFIG_PWMD="$enableval";])
+
+if test "x$CONFIG_PWMD" = xyes; then
+ if test "x$CONFIG_FORMHIST" = xyes; then
+ PKG_CHECK_EXISTS([libpwmd], have_libpwmd=1,
+ AC_MSG_WARN([Could not find libpwmd pkg-config module. Disabling pwmd support.]))
+
+ if test "$have_libpwmd" = 1; then
+ PKG_CHECK_MODULES([libpwmd], [libpwmd >= 2.0.0], have_libpwmd=1)
+
+ if test "$have_libpwmd" = 1; then
+ EL_CONFIG(CONFIG_PWMD, [pwmd])
+ LIBS="$LIBS $libpwmd_LIBS"
+ CFLAGS="$CFLAGS $libpwmd_CFLAGS"
+ else
+ AC_MSG_WARN($libpwmd_PKG_ERRORS)
+ fi
+ fi
+ else
+ AC_MSG_WARN([--enable-pwmd requires --enable-formhist. Disabling pwmd support.])
+ CONFIG_PWMD=no
+ fi
+fi
+
+EL_LOG_CONFIG(CONFIG_PWMD, [Password Manager Daemon], $CONFIG_PWMD)
+
EL_ARG_ENABLE(CONFIG_GLOBHIST, globhist, [Global history],
[ --disable-globhist disable global history support])
diff --git a/features.conf b/features.conf
index 0a756f7..ab9fe20 100644
--- a/features.conf
+++ b/features.conf
@@ -115,6 +115,15 @@ CONFIG_COOKIES=yes
CONFIG_FORMHIST=yes
+### libPWMD Support
+#
+# Storage and retrieval of form data from the Password Manager Daemon.
+#
+# Default: disabled
+
+CONFIG_PWMD=no
+
+
### Global History
#
# This device records each and every page you visit (to a configurable limit).
diff --git a/src/config/actions-main.inc b/src/config/actions-main.inc
index 9626c9d..cd9a55a 100644
--- a/src/config/actions-main.inc
+++ b/src/config/actions-main.inc
@@ -24,6 +24,7 @@ ACTION_(MAIN, "file-menu", FILE_MENU, N__("Open the File menu"), 0),
ACTION_(MAIN, "find-next", FIND_NEXT, N__("Find the next occurrence of the current search text"), ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION),
ACTION_(MAIN, "find-next-back", FIND_NEXT_BACK, N__("Find the previous occurrence of the current search text"), ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION),
ACTION_(MAIN, "forget-credentials", FORGET_CREDENTIALS, N__("Forget authentication credentials"), 0),
+ACTION_(MAIN, "clear-pwmd-cache", CLEAR_PWMD_CACHE, N__("Clear PWMD file cache"), 0),
ACTION_(MAIN, "formhist-manager", FORMHIST_MANAGER, N__("Open form history manager"), 0),
ACTION_(MAIN, "frame-external-command", FRAME_EXTERNAL_COMMAND, N__("Pass URI of current frame to external command"), ACTION_RESTRICT_ANONYMOUS | ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION),
ACTION_(MAIN, "frame-maximize", FRAME_MAXIMIZE, N__("Maximize the current frame"), ACTION_REQUIRE_VIEW_STATE | ACTION_REQUIRE_LOCATION),
diff --git a/src/config/options.inc b/src/config/options.inc
index fe01526..a0d47f1 100644
--- a/src/config/options.inc
+++ b/src/config/options.inc
@@ -169,6 +169,24 @@ static struct option_info config_options_info[] = {
"forms", 0,
N_("Options for handling of the forms interaction.")),
+#ifdef CONFIG_PWMD
+ INIT_OPT_TREE("document.browse.forms", N_("Password Manager Daemon"),
+ "pwmd", 0,
+ N_("Socket and filename settings.")),
+ INIT_OPT_BOOL("document.browse.forms.pwmd", N_("Enable"),
+ "enable", 0, 1,
+ N_("To enable or disable use of the server. If disabled, the\n"
+ "original file base storage will be used.\n")),
+ INIT_OPT_STRING("document.browse.forms.pwmd", N_("Socket location"),
+ "socket", 0, "",
+ N_("To specify the socket to connect to. Defaults to the libpwmd\n"
+ "default of ~/.pwmd/socket if unset.\n")),
+ INIT_OPT_STRING("document.browse.forms.pwmd", N_("Data file"),
+ "filename", 0, "",
+ N_("The filename to open and save to. This option is required to\n"
+ "use the pwmd server.\n")),
+#endif
+
INIT_OPT_BOOL("document.browse.forms", N_("Submit form automatically"),
"auto_submit", 0, 1,
N_("Automagically submit a form when enter is pressed with a text\n"
diff --git a/src/dialogs/menu.c b/src/dialogs/menu.c
index 101d97e..87105e7 100644
--- a/src/dialogs/menu.c
+++ b/src/dialogs/menu.c
@@ -496,6 +496,9 @@ static struct menu_item tools_menu[] = {
#endif
#ifdef CONFIG_FORMHIST
INIT_MENU_ACTION(N_("~Form history"), ACT_MAIN_FORMHIST_MANAGER),
+#ifdef CONFIG_PWMD
+ INIT_MENU_ACTION(N_("C~lear PWMD cache"), ACT_MAIN_CLEAR_PWMD_CACHE),
+#endif
#endif
INIT_MENU_ACTION(N_("~Authentication"), ACT_MAIN_AUTH_MANAGER),
NULL_MENU_ITEM
diff --git a/src/formhist/Makefile b/src/formhist/Makefile
index 9aa0211..dbb6cfd 100644
--- a/src/formhist/Makefile
+++ b/src/formhist/Makefile
@@ -2,5 +2,6 @@ top_builddir=../..
include $(top_builddir)/Makefile.config
OBJS = formhist.o dialogs.o
+OBJS-$(CONFIG_PWMD) += pwmd.o
include $(top_srcdir)/Makefile.lib
diff --git a/src/formhist/README.pwmd b/src/formhist/README.pwmd
new file mode 100644
index 0000000..c715225
--- /dev/null
+++ b/src/formhist/README.pwmd
@@ -0,0 +1,38 @@
+PWMD support enables three new configuration options which can be altered in
+the options GUI or by hand of course:
+
+ document.browse.form.pwmd.enable
+ To enable or disable use of the server. If disabled, the original file
+ based storage will be used.
+
+ document.browse.form.pwmd.socket
+ To specify the socket to connect to. Defaults to the library default
+ of ~/.pwmd/socket if unset.
+
+ document.browse.form.pwmd.filename
+ The filename to open and save to. This is required. You'll get an
+ error if it's unset.
+
+Also added is a Tool menu item to clear the daemons file cache entry. Only the
+file used by Elinks (above) will be cleared. The next open or save to this
+file will require the password.
+
+Make sure gpg-agent is running. If it isn't and the file isn't cached on the
+server, you'll get an error. If gpg-agent is running and you still get an
+error, make sure GPG_AGENT_INFO is set correctly. Read gpg-agent(1) for how to
+set this.
+
+The Form History Manager behavior changes a little when pwmd is enabled. After
+pushing the 'Delete' or 'Clear' buttons, pwmd will remove the URL's from the
+server after confirmation. When pwmd is not enabled, you have to push 'Save'
+to remove an entry from the file like before.
+
+
+TODO:
+Add support for the Authentication Manager.
+
+
+The latest version of the library, daemon/server and application patches can
+be found at http://bjk.sourceforge.net/pwmd/.
+
+Ben Kibbey <[EMAIL PROTECTED]>
diff --git a/src/formhist/dialogs.c b/src/formhist/dialogs.c
index 9eb5fec..bed5142 100644
--- a/src/formhist/dialogs.c
+++ b/src/formhist/dialogs.c
@@ -23,6 +23,10 @@
#include "util/string.h"
#include "viewer/text/form.h"
+#ifdef CONFIG_PWMD
+#include "formhist/pwmd.h"
+#endif
+
static void
lock_formhist_data(struct listbox_item *item)
@@ -112,6 +116,11 @@ delete_formhist_data(struct listbox_item *item, int last)
assert(!is_object_used(formhist_data));
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable"))
+ delete_pwmd_item(formhist_data);
+#endif
+
delete_formhist_item(formhist_data);
}
@@ -200,8 +209,18 @@ push_toggle_dontsave_button(struct dialog_data *dlg_data,
static widget_handler_status_T
push_save_button(struct dialog_data *dlg_data, struct widget_data *button)
{
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable")) {
+ save_pwmd_formhist();
+ return EVENT_PROCESSED;
+ }
+
save_formhist_to_file();
return EVENT_PROCESSED;
+#else
+ save_formhist_to_file();
+ return EVENT_PROCESSED;
+#endif
}
static struct hierbox_browser_button formhist_buttons[] = {
@@ -224,6 +243,14 @@ struct_hierbox_browser(
void
formhist_manager(struct session *ses)
{
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable")) {
+ load_pwmd_formhist(1);
+ hierbox_browser(&formhist_browser, ses);
+ return;
+ }
+#endif
+
load_formhist_from_file();
hierbox_browser(&formhist_browser, ses);
}
diff --git a/src/formhist/formhist.c b/src/formhist/formhist.c
index c1227f0..7e565ee 100644
--- a/src/formhist/formhist.c
+++ b/src/formhist/formhist.c
@@ -25,6 +25,10 @@
#include "util/string.h"
#include "viewer/text/form.h"
+#ifdef CONFIG_PWMD
+#include "formhist/pwmd.h"
+#endif
+
#define FORMS_HISTORY_FILENAME "formhist"
@@ -44,7 +48,7 @@ static struct option_info forms_history_options[] = {
INIT_LIST_HEAD(saved_forms);
-static struct formhist_data *
+struct formhist_data *
new_formhist_item(unsigned char *url)
{
struct formhist_data *form;
@@ -69,7 +73,7 @@ new_formhist_item(unsigned char *url)
return form;
}
-static void
+void
done_formhist_item(struct formhist_data *form)
{
done_listbox_item(&formhist_browser, form->box_item);
@@ -219,6 +223,12 @@ save_formhist_to_file(void)
struct formhist_data *form;
int r;
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable") &&
+ !get_cmd_opt_bool("anonymous"))
+ return save_pwmd_formhist();
+#endif
+
if (!elinks_home || get_cmd_opt_bool("anonymous"))
return 0;
@@ -278,7 +288,16 @@ form_exists(struct formhist_data *form1)
{
struct formhist_data *form;
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable")) {
+ if (!load_pwmd_formhist(0))
+ return 0;
+ }
+ else
+ if (!load_formhist_from_file()) return 0;
+#else
if (!load_formhist_from_file()) return 0;
+#endif
foreach (form, saved_forms) {
int count = 0;
@@ -314,7 +333,7 @@ form_exists(struct formhist_data *form1)
return 0;
}
-static int
+int
forget_forms_with_url(unsigned char *url)
{
struct formhist_data *form, *next;
@@ -355,7 +374,21 @@ get_form_history_value(unsigned char *url, unsigned char *name)
if (!url || !*url || !name || !*name) return NULL;
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable")) {
+ /*
+ * FIXME If theres a pwmd error a message box pops up.
+ * src/viewer/text/form.c seems to call this repeatedly until
+ * it's satisfied with a value.
+ */
+ if (!load_pwmd_formhist(0))
+ return NULL;
+ }
+ else
+ if (!load_formhist_from_file()) return NULL;
+#else
if (!load_formhist_from_file()) return NULL;
+#endif
foreach (form, saved_forms) {
if (form->dontsave) continue;
@@ -409,6 +442,27 @@ memorize_form(struct session *ses, struct list_head *submit,
if (form_exists(form)) goto fail;
+#ifdef CONFIG_PWMD
+ if (get_opt_bool("document.browse.forms.pwmd.enable"))
+ msg_box(ses->tab->term, NULL, 0,
+ N_("Form history"), ALIGN_CENTER,
+ N_("Should this login be remembered?\n\n"),
+ form, 3,
+ N_("~Yes"), remember_form, B_ENTER,
+ N_("~No"), done_formhist_item, B_ESC,
+ N_("Ne~ver for this site"), never_for_this_site, NULL);
+ else
+ msg_box(ses->tab->term, NULL, 0,
+ N_("Form history"), ALIGN_CENTER,
+ N_("Should this login be remembered?\n\n"
+ "Please note that the password will be stored "
+ "obscured (but unencrypted) in a file on your disk.\n\n"
+ "If you are using a valuable password, answer NO."),
+ form, 3,
+ N_("~Yes"), remember_form, B_ENTER,
+ N_("~No"), done_formhist_item, B_ESC,
+ N_("Ne~ver for this site"), never_for_this_site, NULL);
+#else
msg_box(ses->tab->term, NULL, 0,
N_("Form history"), ALIGN_CENTER,
N_("Should this login be remembered?\n\n"
@@ -420,6 +474,7 @@ memorize_form(struct session *ses, struct list_head *submit,
N_("~No"), done_formhist_item, B_ESC,
N_("Ne~ver for this site"), never_for_this_site, NULL);
+#endif
return;
fail:
@@ -437,7 +492,11 @@ done_form_history(struct module *module)
}
struct module forms_history_module = struct_module(
+#ifdef CONFIG_PWMD
+ /* name: */ N_("Form History (PWMD support)"),
+#else
/* name: */ N_("Form History"),
+#endif
/* options: */ forms_history_options,
/* events: */ NULL,
/* submodules: */ NULL,
diff --git a/src/formhist/formhist.h b/src/formhist/formhist.h
index 3be6622..0f7b29a 100644
--- a/src/formhist/formhist.h
+++ b/src/formhist/formhist.h
@@ -28,9 +28,12 @@ unsigned char *get_form_history_value(unsigned char *url, unsigned char *name);
void memorize_form(struct session *ses, struct list_head *submit, struct form *forminfo);
+extern struct list_head saved_forms;
int save_formhist_to_file(void);
-void delete_formhist_item(struct formhist_data *form);
int load_formhist_from_file(void);
+int forget_forms_with_url(unsigned char *url);
+struct formhist_data * new_formhist_item(unsigned char *url);
+void done_formhist_item(struct formhist_data *form);
extern struct module forms_history_module;
diff --git a/src/formhist/pwmd.c b/src/formhist/pwmd.c
new file mode 100644
index 0000000..08395dd
--- /dev/null
+++ b/src/formhist/pwmd.c
@@ -0,0 +1,582 @@
+/*
+ * When --enable-pwmd is passed to configure and pwmd is enabled in the Elinks
+ * configuration, Elinks will store and retrieve form data with pwmd (Password
+ * Manager Daemon). The daemon listens on a local socket and the client must
+ * provide a password to open the file that contains the wanted data. libpwmd
+ * makes it easy to communicate with the daemon and uses gpg-agent for
+ * password retrieval (pinentry).
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <libpwmd.h>
+
+#include "elinks.h"
+#include "formhist/pwmd.h"
+#include "intl/gettext/libintl.h"
+#include "util/string.h"
+#include "viewer/text/form.h"
+
+static int did_error;
+static int last_errno;
+
+static void
+show_error(int ret, int error)
+{
+ unsigned char *buf;
+ struct terminal *term = terminals.prev;
+
+ if (ret == PWMD_PERROR && error == EPWMD_EMPTY_ELEMENT)
+ return;
+
+ if (ret == PWMD_PERROR)
+ buf = msg_text(term, N_("Error %03i: %s\n"), error, pwmd_strerror(error));
+ else if (error == -1)
+ buf = msg_text(term, N_("No data filename has been specified in Document->Forms->PWMD."));
+ else if (ret == PWMD_ERROR)
+ buf = msg_text(term, N_("%s\n"), strerror(error));
+ else if (ret == PWMD_AGENT_ERROR)
+ buf = msg_text(term, N_("%s"), "gpg-agent failed. Is gpg-agent running? Is "
+ "GPG_AGENT_INFO set?");
+ else
+ return;
+
+ info_box(term, MSGBOX_FREE_TEXT, "Password Manager Daemon", ALIGN_LEFT, buf);
+}
+
+static int
+set_agent_strings(pwm_t *pwm, const char *filename, int *ret, int *error,
+ int save)
+{
+ char *result;
+ struct string str;
+
+ if (init_string(&str) == NULL)
+ goto fail;
+
+ if ((*ret = pwmd_command(pwm, &result, error, PWMD_SETOPT,
+ PWMD_OPTION_USEAGENT, 1)) != PWMD_OK)
+ goto fail;
+
+ add_format_to_string(&str, "Password Manager Daemon: Elinks");
+
+ if ((*ret = pwmd_command(pwm, &result, error, PWMD_SETOPT,
+ PWMD_OPTION_TITLE, str.source)) != PWMD_OK)
+ goto fail;
+
+ str.length = 0;
+ add_format_to_string(&str,
+ "A password is required to %s the file '%s'. Please \n"
+ "enter the password below.", (save) ? "save to" : "open",
+ filename);
+
+ if ((*ret = pwmd_command(pwm, &result, error, PWMD_SETOPT,
+ PWMD_OPTION_DESC, str.source))
+ != PWMD_OK)
+ goto fail;
+
+ done_string(&str);
+ return 1;
+
+fail:
+ done_string(&str);
+ return 0;
+}
+
+static pwm_t *
+do_connect(char **file, int *ret, int *error)
+{
+ char *filename = get_opt_str("document.browse.forms.pwmd.filename");
+ char *socket;
+ pwm_t *pwm;
+
+ *ret = PWMD_ERROR;
+
+ if (!filename || !*filename) {
+ *error = -1;
+ return NULL;
+ }
+
+ *file = filename;
+ socket = get_opt_str("document.browse.forms.pwmd.socket");
+
+ if (!socket || !*socket)
+ socket = NULL;
+
+ if ((pwm = pwmd_connect(socket, error)) == NULL)
+ return NULL;
+
+ if (!set_agent_strings(pwm, filename, ret, error, 0)) {
+ pwmd_close(pwm);
+ return NULL;
+ }
+
+ return pwm;
+}
+
+void
+clear_pwmd_cache()
+{
+ struct string str;
+ pwm_t *pwm;
+ int ret, error;
+ char *filename;
+ char *result;
+
+ if ((pwm = do_connect(&filename, &ret, &error)) == NULL) {
+ show_error(ret, error);
+ return;
+ }
+
+ if (!init_string(&str)) {
+ pwmd_close(pwm);
+ return;
+ }
+
+ add_format_to_string(&str, "CACHE CLEAR %s\n", filename);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND, str.source))
+ != PWMD_OK) {
+ if (ret != PWMD_PERROR || (error != EPWMD_CACHE_NOT_FOUND &&
+ error != EPWMD_FILE_NOT_FOUND))
+ show_error(ret, error);
+ }
+
+ pwmd_close(pwm);
+ done_string(&str);
+}
+
+/*
+ * This function is only called from dialog.c. The way the regular formhist
+ * manager does it is that the form isn't removed from the file until the
+ * 'Save' button is pushed. With pwmd, the 'Delete' (or 'Clear') button will
+ * remove the URL from the server after confirmation without pushing 'Save'.
+ */
+void
+delete_pwmd_item(struct formhist_data *form)
+{
+ pwm_t *pwm;
+ int ret, error;
+ char *filename;
+ struct string str;
+ char *result;
+
+ if ((pwm = do_connect(&filename, &ret, &error)) == NULL) {
+ show_error(ret, error);
+ return;
+ }
+
+ if (init_string(&str) == NULL)
+ goto done;
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_OPEN, filename))
+ != PWMD_OK) {
+ show_error(ret, error);
+ goto done;
+ }
+
+ add_format_to_string(&str, "DELETE %s\n", form->url);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND, str.source))
+ != PWMD_OK) {
+ show_error(ret, error);
+ goto done;
+ }
+
+ if (!set_agent_strings(pwm, filename, &ret, &error, 1)) {
+ show_error(ret, error);
+ goto done;
+ }
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_SAVE)) != PWMD_OK) {
+ show_error(ret, error);
+ goto done;
+ }
+
+done:
+ pwmd_close(pwm);
+ done_string(&str);
+}
+
+/*
+ * FIXME
+ * Same problem with gpg-agent and invalid passwords as pwmd_load_formhist().
+ */
+/*
+ * Stores the form data on the server. The "account" name is form->url with an
+ * attribute created_by="elinks". Each submitted value (sv->name) is stored as
+ * child of form->url with an attribute of "type". The sv->value is the
+ * element (sv->name) value/PCDATA.
+ */
+int
+save_pwmd_formhist(void)
+{
+ struct formhist_data *form;
+ pwm_t *pwm;
+ int error;
+ int ret = PWMD_ERROR;
+ char *result;
+ char *filename = NULL;
+ int cached = 0;
+ struct string str;
+ struct terminal *term = terminals.prev;
+
+ if ((pwm = do_connect(&filename, &ret, &error)) == NULL) {
+ show_error(ret, error);
+ return 0;
+ }
+
+ if (init_string(&str) == NULL) {
+ pwmd_close(pwm);
+ return 0;
+ }
+
+ /*
+ * Avoid a redraw if the file is cached (gpg-agent).
+ */
+ add_format_to_string(&str, "CACHE ISCACHED %s\n", filename);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) == PWMD_OK)
+ cached = 1;
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_OPEN, filename))
+ != PWMD_OK)
+ goto fail;
+
+ if (!cached) {
+ if (term->redrawing == TREDRAW_READY)
+ redraw_terminal_cls(term);
+ }
+
+ foreach (form, saved_forms) {
+ struct submitted_value *sv;
+
+ str.length = 0;
+ add_format_to_string(&str, "ATTR SET dontsave %s %i\n",
+ form->url, form->dontsave);
+ ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND, str.source);
+
+ if (form->dontsave)
+ continue;
+
+ str.length = 0;
+ add_format_to_string(&str, "STORE %s\n", form->url);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) != PWMD_OK)
+ continue;
+
+ str.length = 0;
+ add_format_to_string(&str,
+ "ATTR SET created_by %s elinks\n", form->url);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) != PWMD_OK)
+ continue;
+
+ foreach (sv, *form->submit) {
+ str.length = 0;
+ add_format_to_string(&str,
+ "STORE %s\t%s\t%s\n", form->url,
+ sv->name, sv->value);
+
+ if ((ret = pwmd_command(pwm, &result, &error,
+ PWMD_COMMAND,
+ str.source)) != PWMD_OK)
+ continue;
+
+ str.length = 0;
+ add_format_to_string(&str,
+ "ATTR SET type %s\t%s %s\n", form->url,
+ sv->name, form_type2str(sv->type));
+
+ if ((ret = pwmd_command(pwm, &result, &error,
+ PWMD_COMMAND,
+ str.source)) != PWMD_OK)
+ continue;
+ }
+ }
+
+ if (!set_agent_strings(pwm, filename, &ret, &error, 1))
+ goto fail;
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_SAVE)) != PWMD_OK)
+ goto fail;
+
+ done_string(&str);
+ pwmd_close(pwm);
+ redraw_terminal_cls(term);
+ return 1;
+
+fail:
+ done_string(&str);
+ pwmd_close(pwm);
+ show_error(ret, error);
+ redraw_terminal_cls(term);
+ return 0;
+}
+
+static int
+elinks_account(pwm_t *pwm, const char *account)
+{
+ char *result;
+ int error;
+ int ret;
+ struct string str;
+
+ if (init_string(&str) == NULL)
+ return 0;
+
+ str.length = 0;
+ add_format_to_string(&str, "ATTR GET created_by %s\n",
+ account);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) != PWMD_OK) {
+ if (ret == PWMD_ERROR ||
+ (ret == PWMD_PERROR && error != EPWMD_ATTR_NOT_FOUND))
+ show_error(ret, error);
+
+ done_string(&str);
+ return 0;
+ }
+
+ done_string(&str);
+
+ if (strcmp(result, "elinks") == 0) {
+ free(result);
+ return 1;
+ }
+
+ free(result);
+ return 0;
+}
+
+static int
+get_form_values(pwm_t *pwm, char *account)
+{
+ char *result;
+ int error;
+ char *l, *p;
+ struct formhist_data *form;
+ int ret;
+ int dontsave = 0;
+ struct string str;
+ int match = 0;
+
+ if (init_string(&str) == NULL)
+ return 0;
+
+ str.length = 0;
+ add_format_to_string(&str, "ATTR GET dontsave %s\n", account);
+ ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND, str.source);
+
+ if (ret == PWMD_OK) {
+ dontsave = atoi((char *)result);
+ free(result);
+ }
+
+ str.length = 0;
+ add_format_to_string(&str, "LIST %s\n", account);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) != PWMD_OK) {
+ show_error(ret, error);
+ done_string(&str);
+ return 0;
+ }
+
+ if ((form = new_formhist_item(account)) == NULL) {
+ free(result);
+ goto fail;
+ }
+
+ form->dontsave = dontsave;
+ l = result;
+
+ while ((p = strsep(&l, "\n")) != NULL) {
+ char *t;
+ struct submitted_value *sv;
+ enum form_type ftype;
+ unsigned char *name = NULL, *value = NULL;
+
+ /*
+ * Look for an attribute "type" and see if it's a recognized
+ * type.
+ */
+ str.length = 0;
+ add_format_to_string(&str, "ATTR GET type %s\n", p);
+
+ if (pwmd_command(pwm, &t, &error, PWMD_COMMAND, str.source) != PWMD_OK)
+ continue;
+
+ if ((ftype = str2form_type(t)) == -1) {
+ free(t);
+ continue;
+ }
+
+ /*
+ * Get the value for the current element path.
+ */
+ str.length = 0;
+ add_format_to_string(&str, "GET %s\n", p);
+
+ if (pwmd_command(pwm, &t, &error, PWMD_COMMAND, str.source) != PWMD_OK)
+ continue;
+
+ value = t;
+
+ /*
+ * The element/form "name" is the last element in the element
+ * path.
+ */
+ p = strrchr(p, '\t');
+ p++;
+ name = strdup((char *)p);
+
+ /*
+ * Append to the form.
+ */
+ if ((sv = init_submitted_value(name, value, ftype, NULL, 0)) == NULL) {
+ free(name);
+ free(value);
+ free(result);
+ goto fail;
+ }
+
+ add_to_list(*form->submit, sv);
+ free(name);
+ free(value);
+ match = 1;
+ }
+
+ free(result);
+
+ if (!match)
+ goto fail;
+
+ done_string(&str);
+ forget_forms_with_url(form->url);
+ add_to_list(saved_forms, form);
+ return 1;
+
+fail:
+ done_string(&str);
+ done_formhist_item(form);
+ return 0;
+}
+
+/*
+ * FIXME
+ * If a bad password is specified then elinks keeps calling this function and
+ * gpg-agent. It should give up after a count.
+ */
+int
+load_pwmd_formhist(int reload_form)
+{
+ pwm_t *pwm = NULL;
+ int error = -1;
+ char *result;
+ char *l, *p;
+ int ret = PWMD_ERROR;
+ char *filename = NULL;
+ int cached = 0;
+ struct string str;
+ struct terminal *term = terminals.prev;
+ static int loaded;
+
+ if (loaded && !reload_form) return 1;
+
+ loaded = 0;
+
+ if (init_string(&str) == NULL)
+ goto fail;
+
+ if ((pwm = do_connect(&filename, &ret, &error)) == NULL)
+ goto fail;
+
+ /*
+ * Avoid a redraw if the file is cached (gpg-agent).
+ */
+ str.length = 0;
+ add_format_to_string(&str, "CACHE ISCACHED %s\n", filename);
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) == PWMD_OK)
+ cached = 1;
+ else {
+ if (ret == PWMD_PERROR && error == EPWMD_FILE_NOT_FOUND) {
+ done_string(&str);
+ pwmd_close(pwm);
+ return 1;
+ }
+ }
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_OPEN, filename))
+ != PWMD_OK)
+ goto fail;
+
+ if (!cached && !loaded) {
+ if (term->redrawing == TREDRAW_READY)
+ redraw_terminal_cls(term);
+ }
+
+ /*
+ * Get a list of "account"s or root elements.
+ */
+ str.length = 0;
+ add_format_to_string(&str, "LIST\n");
+
+ if ((ret = pwmd_command(pwm, &result, &error, PWMD_COMMAND,
+ str.source)) != PWMD_OK)
+ goto fail;
+
+ l = result;
+
+ while ((p = strsep(&l, "\n")) != NULL) {
+ /*
+ * Find a "created_by" attribute with an "elinks" value.
+ */
+ if (!elinks_account(pwm, p))
+ continue;
+
+ /*
+ * For every element in the current tree append to the form.
+ */
+ if (get_form_values(pwm, p))
+ continue;
+ }
+
+ free(result);
+ done_string(&str);
+ did_error = 0;
+ pwmd_close(pwm);
+ loaded = 1;
+ return 1;
+
+fail:
+ done_string(&str);
+
+ if (pwm)
+ pwmd_close(pwm);
+
+ if (!did_error) {
+ show_error(ret, error);
+ did_error = 1;
+ last_errno = error;
+ pwm = NULL;
+ }
+
+ /*
+ * Error "stacking".
+ */
+ if (pwm) {
+ if (last_errno != error)
+ show_error(ret, error);
+ }
+
+ return 0;
+}
diff --git a/src/formhist/pwmd.h b/src/formhist/pwmd.h
new file mode 100644
index 0000000..8a8e469
--- /dev/null
+++ b/src/formhist/pwmd.h
@@ -0,0 +1,11 @@
+#ifndef EL__FORMHIST_PWMD_H
+#define EL__FORMHIST_PWMD_H
+
+#include "formhist/formhist.h"
+
+int load_pwmd_formhist(int reload_form);
+int save_pwmd_formhist(void);
+void delete_pwmd_item(struct formhist_data *form);
+void clear_pwmd_cache(void);
+
+#endif /* EL__FORMHIST_PWMD_H */
diff --git a/src/viewer/action.c b/src/viewer/action.c
index 3089a19..6ca092b 100644
--- a/src/viewer/action.c
+++ b/src/viewer/action.c
@@ -44,6 +44,10 @@
#include "viewer/text/search.h"
#include "viewer/text/view.h"
+#ifdef CONFIG_PWMD
+#include "formhist/pwmd.h"
+#endif
+
static void
goto_url_action(struct session *ses,
@@ -205,6 +209,11 @@ do_action(struct session *ses, enum main_action action_id, int verbose)
status = find_next(ses, doc_view, -1);
break;
+#ifdef CONFIG_PWMD
+ case ACT_MAIN_CLEAR_PWMD_CACHE:
+ clear_pwmd_cache();
+ break;
+#endif
case ACT_MAIN_FORGET_CREDENTIALS:
free_auth();
shrink_memory(1); /* flush caches */
@@ -215,7 +224,6 @@ do_action(struct session *ses, enum main_action action_id, int verbose)
formhist_manager(ses);
#endif
break;
-
case ACT_MAIN_FRAME_EXTERNAL_COMMAND:
status = pass_uri_to_command(ses, doc_view,
PASS_URI_FRAME);
diff --git a/src/viewer/text/form.c b/src/viewer/text/form.c
index f37673c..306c4e1 100644
--- a/src/viewer/text/form.c
+++ b/src/viewer/text/form.c
@@ -1172,8 +1172,8 @@ get_form_uri(struct session *ses, struct document_view *doc_view,
* a file that is to be uploaded. TODO: Distinguish between
* these two classes of errors (is it worth it?). -- Miciah */
if (data.source
- && get_opt_bool("document.browse.forms.show_formhist"))
- memorize_form(ses, &submit, form);
+ && get_opt_bool("document.browse.forms.show_formhist"))
+ memorize_form(ses, &submit, form);
#endif
done_submitted_value_list(&submit);
signature.asc
Description: Digital signature
_______________________________________________ elinks-dev mailing list [email protected] http://linuxfromscratch.org/mailman/listinfo/elinks-dev
