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);

Attachment: signature.asc
Description: Digital signature

_______________________________________________
elinks-dev mailing list
elinks-dev@linuxfromscratch.org
http://linuxfromscratch.org/mailman/listinfo/elinks-dev

Reply via email to