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 elinks-dev@linuxfromscratch.org http://linuxfromscratch.org/mailman/listinfo/elinks-dev