From 337f9948d51d48f8b2a01694e07ea1bf4fa337af Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 28 Dec 2016 15:23:34 +0000 Subject: Update RISC OS ssl certificate viewer to core window interface --- frontends/riscos/dialog.c | 2 +- frontends/riscos/gui.c | 3 - frontends/riscos/gui.h | 5 - frontends/riscos/sslcert.c | 496 ++++++++++++++++++++++++++------------------- frontends/riscos/sslcert.h | 27 ++- 5 files changed, 304 insertions(+), 229 deletions(-) (limited to 'frontends/riscos') diff --git a/frontends/riscos/dialog.c b/frontends/riscos/dialog.c index 1e6ae5591..94c62354b 100644 --- a/frontends/riscos/dialog.c +++ b/frontends/riscos/dialog.c @@ -181,7 +181,7 @@ void ro_gui_dialog_init(void) */ /* certificate verification window */ - ro_gui_cert_preinitialise(); + ro_gui_cert_initialise(); /* hotlist window */ ro_gui_hotlist_initialise(); diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c index 1f56798f9..a534bceff 100644 --- a/frontends/riscos/gui.c +++ b/frontends/riscos/gui.c @@ -1268,9 +1268,6 @@ static nserror gui_init(int argc, char** argv) /* Finally, check Inet$Resolvers for sanity */ ro_gui_check_resolvers(); - /* certificate verification window */ - ro_gui_cert_postinitialise(); - open_window = nsoption_bool(open_browser_at_startup); /* parse command-line arguments */ diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h index 505e8e755..1f5070012 100644 --- a/frontends/riscos/gui.h +++ b/frontends/riscos/gui.h @@ -211,11 +211,6 @@ extern int ro_plot_origin_y; /* in theme_install.c */ bool ro_gui_theme_install_apply(wimp_w w); -/* in sslcert.c */ -nserror gui_cert_verify(struct nsurl *url, - const struct ssl_cert_info *certs, unsigned long num, - nserror (*cb)(bool proceed, void *pw), void *cbpw); - /* icon numbers */ #define ICON_STATUS_RESIZE 0 #define ICON_STATUS_TEXT 1 diff --git a/frontends/riscos/sslcert.c b/frontends/riscos/sslcert.c index 8a8ddfb5b..85b84456e 100644 --- a/frontends/riscos/sslcert.c +++ b/frontends/riscos/sslcert.c @@ -1,6 +1,6 @@ /* * Copyright 2006 John M Bell - * Copyright 2010 Stephen Fryatt + * Copyright 2016 Vincent Sanders * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -17,329 +17,399 @@ * along with this program. If not, see . */ -/** \file - * SSL Certificate verification UI (implementation) +/** + * \file + * Implementation of RISC OS certificate verification UI. */ -#include "utils/config.h" - -#include -#include -#include -#include -#include "oslib/wimp.h" +#include #include "utils/log.h" +#include "netsurf/plotters.h" #include "desktop/sslcert_viewer.h" -#include "desktop/tree.h" #include "riscos/dialog.h" -#include "riscos/sslcert.h" -#include "riscos/textarea.h" -#include "riscos/treeview.h" #include "riscos/wimp.h" #include "riscos/wimp_event.h" #include "riscos/wimputils.h" #include "riscos/gui.h" +#include "riscos/toolbar.h" +#include "riscos/corewindow.h" +#include "riscos/sslcert.h" +/* widget ID */ #define ICON_SSL_PANE 1 #define ICON_SSL_REJECT 3 #define ICON_SSL_ACCEPT 4 -static wimp_window *ro_gui_cert_dialog_template; -static wimp_window *ro_gui_cert_tree_template; +/** + * RISC OS certificate viewer context. + */ +struct ro_cert_window { + struct ro_corewindow core; + + /** certificate view window handle */ + wimp_w wh; + + /** SSL certificate viewer context data */ + struct sslcert_session_data *ssl_data; -struct ro_sslcert -{ - wimp_w window; - wimp_w pane; - ro_treeview *tv; - struct sslcert_session_data *data; }; -static void ro_gui_cert_accept(wimp_pointer *pointer); -static void ro_gui_cert_reject(wimp_pointer *pointer); -static void ro_gui_cert_close_window(wimp_w w); -static void ro_gui_cert_release_window(struct ro_sslcert *s); +/** riscos dialog template for certificate viewer window. */ +static wimp_window *dialog_cert_template; + +/** riscos template for certificate tree pane. */ +static wimp_window *cert_tree_template; + /** - * Load and initialise the certificate window template + * Handle closing of the RISC OS certificate verification dialog + * + * Deleting wimp windows, freeing up the core window and ssl data block. + * + * \param certw The context associated with the dialogue. */ - -void ro_gui_cert_preinitialise(void) +static void ro_gui_cert_release_window(struct ro_cert_window *certw) { - /* Load templates for the SSL windows and adjust the tree window - * flags to suit. - */ + os_error *error; + + ro_gui_wimp_event_finalise(certw->wh); + + sslcert_viewer_fini(certw->ssl_data); - ro_gui_cert_dialog_template = ro_gui_dialog_load_template("sslcert"); - ro_gui_cert_tree_template = ro_gui_dialog_load_template("tree"); + ro_corewindow_fini(&certw->core); + + error = xwimp_delete_window(certw->wh); + if (error) { + LOG("xwimp_delete_window: 0x%x:%s", + error->errnum, error->errmess); + } - ro_gui_cert_tree_template->flags &= ~(wimp_WINDOW_MOVEABLE | - wimp_WINDOW_BACK_ICON | - wimp_WINDOW_CLOSE_ICON | - wimp_WINDOW_TITLE_ICON | - wimp_WINDOW_SIZE_ICON | - wimp_WINDOW_TOGGLE_ICON); + error = xwimp_delete_window(certw->core.wh); + if (error) { + LOG("xwimp_delete_window: 0x%x:%s", + error->errnum, error->errmess); + } + + free(certw); } /** - * Load and initialise the certificate window template + * Handle acceptance of certificate via event callback. + * + * \param pointer The wimp pointer event. */ - -void ro_gui_cert_postinitialise(void) +static void ro_gui_cert_accept(wimp_pointer *pointer) { - /* Initialise the SSL module. */ + struct ro_cert_window *certw; + certw = (struct ro_cert_window *)ro_gui_wimp_event_get_user_data(pointer->w); + + sslcert_viewer_accept(certw->ssl_data); + ro_gui_dialog_close(certw->wh); + ro_gui_cert_release_window(certw); } + /** - * Prompt the user to verify a certificate with issuse. + * Handle rejection of certificate via event callback. * - * \param url The URL being verified. - * \param certs The certificate to be verified - * \param num The number of certificates to be verified. - * \param cb Callback upon user decision. - * \param cbpw Context pointer passed to cb + * \param pointer The wimp pointer block. */ -nserror gui_cert_verify(nsurl *url, - const struct ssl_cert_info *certs, unsigned long num, - nserror (*cb)(bool proceed, void *pw), void *cbpw) +static void ro_gui_cert_reject(wimp_pointer *pointer) { - struct ro_sslcert *sslcert_window; - wimp_window_state state; - wimp_icon_state istate; - wimp_window_info info; - os_error *error; - bool set_extent; - - assert(certs); - - sslcert_window = malloc(sizeof(struct ro_sslcert)); - if (sslcert_window == NULL) { - LOG("Failed to allocate memory for SSL Cert Dialog"); - return NSERROR_NOMEM; - } + struct ro_cert_window *certw; + certw = (struct ro_cert_window *)ro_gui_wimp_event_get_user_data(pointer->w); - /* Create the SSL window and its pane. */ + sslcert_viewer_reject(certw->ssl_data); + ro_gui_dialog_close(certw->wh); + ro_gui_cert_release_window(certw); +} - error = xwimp_create_window(ro_gui_cert_dialog_template, - &(sslcert_window->window)); - if (error) { - LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess); - free(sslcert_window); - return NSERROR_INIT_FAILED; - } - error = xwimp_create_window(ro_gui_cert_tree_template, - &(sslcert_window->pane)); - if (error) { - LOG("xwimp_create_window: 0x%x: %s", error->errnum, error->errmess); - free(sslcert_window); - return NSERROR_INIT_FAILED; - } +/** + * Callback to handle the closure of the SSL dialogue by other means. + * + * \param w The window handle being closed. + */ +static void ro_gui_cert_close_window(wimp_w w) +{ + struct ro_cert_window *certw; + certw = (struct ro_cert_window *)ro_gui_wimp_event_get_user_data(w); - /* Create the SSL data and build a tree from it. */ - sslcert_viewer_create_session_data(num, url, - cb, cbpw, certs, &sslcert_window->data); - ssl_current_session = sslcert_window->data; + ro_gui_cert_release_window(certw); +} - sslcert_window->tv = ro_treeview_create(sslcert_window->pane, - NULL, NULL, TREE_SSLCERT); - if (sslcert_window->tv == NULL) { - LOG("Failed to allocate treeview"); - free(sslcert_window); - return NSERROR_NOMEM; - } - /* Set up the certificate window event handling. - * - * (The action buttons are registered as button events, not OK and - * Cancel, as both need to carry out actions.) - */ - - ro_gui_wimp_event_set_user_data(sslcert_window->window, sslcert_window); - ro_gui_wimp_event_register_close_window(sslcert_window->window, - ro_gui_cert_close_window); - ro_gui_wimp_event_register_button(sslcert_window->window, - ICON_SSL_REJECT, ro_gui_cert_reject); - ro_gui_wimp_event_register_button(sslcert_window->window, - ICON_SSL_ACCEPT, ro_gui_cert_accept); - - ro_gui_dialog_open_persistent(NULL, sslcert_window->window, false); - - /* Nest the tree window inside the pane window. To do this, we: - * - Get the current pane extent, - * - Get the parent window position and the location of the pane- - * locating icon inside it, - * - Set the visible area of the pane to suit, - * - Check that the pane extents are OK for this visible area, and - * increase them if necessary, - * - Before finally opening the pane as a nested part of the parent. - */ +/** + * Attach tree window as a pane to ssl window. + * + * Nest the tree window inside the pane window. To do this, we: + * - Get the current pane extent, + * - Get the parent window position and the location of the pane- + * locating icon inside it, + * - Set the visible area of the pane to suit, + * - Check that the pane extents are OK for this visible area, and + * increase them if necessary, + * - Before finally opening the pane as a nested part of the parent. + * + */ +static nserror cert_attach_pane(wimp_w parent, wimp_w pane) +{ + os_error *error; + wimp_window_state wstate; + wimp_window_info winfo; + wimp_icon_state istate; + bool set_extent; - info.w = sslcert_window->pane; - error = xwimp_get_window_info_header_only(&info); + winfo.w = pane; + error = xwimp_get_window_info_header_only(&winfo); if (error) { - ro_gui_cert_release_window(sslcert_window); - LOG("xwimp_get_window_info: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_get_window_info: 0x%x: %s", + error->errnum, error->errmess); return NSERROR_INIT_FAILED; } - state.w = sslcert_window->window; - error = xwimp_get_window_state(&state); + wstate.w = parent; + error = xwimp_get_window_state(&wstate); if (error) { - ro_gui_cert_release_window(sslcert_window); - LOG("xwimp_get_window_state: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess); return NSERROR_INIT_FAILED; } - istate.w = sslcert_window->window; + istate.w = parent; istate.i = ICON_SSL_PANE; error = xwimp_get_icon_state(&istate); if (error) { - ro_gui_cert_release_window(sslcert_window); - LOG("xwimp_get_icon_state: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_get_icon_state: 0x%x: %s", + error->errnum, error->errmess); return NSERROR_INIT_FAILED; } - state.w = sslcert_window->pane; - state.visible.x1 = state.visible.x0 + istate.icon.extent.x1 - 20 - - ro_get_vscroll_width(sslcert_window->pane); - state.visible.x0 += istate.icon.extent.x0 + 20; - state.visible.y0 = state.visible.y1 + istate.icon.extent.y0 + 20 + - ro_get_hscroll_height(sslcert_window->pane); - state.visible.y1 += istate.icon.extent.y1 - 32; + wstate.w = pane; + wstate.visible.x1 = wstate.visible.x0 + istate.icon.extent.x1 - 20 - ro_get_vscroll_width(pane); + wstate.visible.x0 += istate.icon.extent.x0 + 20; + wstate.visible.y0 = wstate.visible.y1 + istate.icon.extent.y0 + 20 + ro_get_hscroll_height(pane); + wstate.visible.y1 += istate.icon.extent.y1 - 32; set_extent = false; - if ((info.extent.x1 - info.extent.x0) < - (state.visible.x1 - state.visible.x0)) { - info.extent.x0 = 0; - info.extent.x1 = state.visible.x1 - state.visible.x0; + if ((winfo.extent.x1 - winfo.extent.x0) < + (wstate.visible.x1 - wstate.visible.x0)) { + winfo.extent.x0 = 0; + winfo.extent.x1 = wstate.visible.x1 - wstate.visible.x0; set_extent = true; } - if ((info.extent.y1 - info.extent.y0) < - (state.visible.y1 - state.visible.y0)) { - info.extent.y1 = 0; - info.extent.x1 = state.visible.y0 - state.visible.y1; + if ((winfo.extent.y1 - winfo.extent.y0) < + (wstate.visible.y1 - wstate.visible.y0)) { + winfo.extent.y1 = 0; + winfo.extent.x1 = wstate.visible.y0 - wstate.visible.y1; set_extent = true; } if (set_extent) { - error = xwimp_set_extent(sslcert_window->pane, &(info.extent)); + error = xwimp_set_extent(pane, &(winfo.extent)); if (error) { - ro_gui_cert_release_window(sslcert_window); - LOG("xwimp_set_extent: 0x%x: %s", error->errnum, error->errmess); + LOG("xwimp_set_extent: 0x%x: %s", + error->errnum, error->errmess); return NSERROR_INIT_FAILED; } } - error = xwimp_open_window_nested(PTR_WIMP_OPEN(&state), - sslcert_window->window, - wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT - << wimp_CHILD_XORIGIN_SHIFT | - wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT - << wimp_CHILD_YORIGIN_SHIFT | - wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT - << wimp_CHILD_LS_EDGE_SHIFT | - wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT - << wimp_CHILD_RS_EDGE_SHIFT); + error = xwimp_open_window_nested( + PTR_WIMP_OPEN(&wstate), + parent, + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT << wimp_CHILD_XORIGIN_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_TOP_OR_RIGHT << wimp_CHILD_YORIGIN_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT << wimp_CHILD_LS_EDGE_SHIFT | + wimp_CHILD_LINKS_PARENT_VISIBLE_BOTTOM_OR_LEFT << wimp_CHILD_RS_EDGE_SHIFT); if (error) { - ro_gui_cert_release_window(sslcert_window); - LOG("xwimp_open_window_nested: 0x%x: %s", error->errnum, error->errmess); - ro_gui_cert_release_window(sslcert_window); + LOG("xwimp_open_window_nested: 0x%x: %s", + error->errnum, error->errmess); return NSERROR_INIT_FAILED; } - ro_treeview_set_origin(sslcert_window->tv, 0, 0); - return NSERROR_OK; } + /** - * Handle acceptance of certificate via event callback. + * Callback to draw on drawable area of ro certificate viewer window. * - * \param *pointer The wimp pointer block. + * \param ro_cw The riscos core window structure. + * \param originx The risc os plotter x origin. + * \param originy The risc os plotter y origin. + * \param r The rectangle of the window that needs updating. + * \return NSERROR_OK on success otherwise apropriate error code */ - -void ro_gui_cert_accept(wimp_pointer *pointer) +static nserror +cert_draw(struct ro_corewindow *ro_cw, int originx, int originy, struct rect *r) { - struct ro_sslcert *s; + struct ro_cert_window *certw; + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &ro_plotters + }; - s = (struct ro_sslcert *) ro_gui_wimp_event_get_user_data(pointer->w); + certw = (struct ro_cert_window *)ro_cw; - if (s != NULL) { - sslcert_viewer_accept(s->data); - ro_gui_dialog_close(s->window); - ro_gui_cert_release_window(s); - } + ro_plot_origin_x = originx; + ro_plot_origin_y = originy; + no_font_blending = true; + sslcert_viewer_redraw(certw->ssl_data, 0, 0, r, &ctx); + no_font_blending = false; + + return NSERROR_OK; } + /** - * Handle rejection of certificate via event callback. + * callback for keypress on ro certificate viewer window * - * \param pointer The wimp pointer block. + * \param ro_cw The ro core window structure. + * \param nskey The netsurf key code. + * \return NSERROR_OK if key processed, + * NSERROR_NOT_IMPLEMENTED if key not processed + * otherwise apropriate error code */ - -void ro_gui_cert_reject(wimp_pointer *pointer) +static nserror cert_key(struct ro_corewindow *ro_cw, uint32_t nskey) { - struct ro_sslcert *s; + struct ro_cert_window *certw; + certw = (struct ro_cert_window *)ro_cw; - s = (struct ro_sslcert *) ro_gui_wimp_event_get_user_data(pointer->w); - - if (s != NULL) { - sslcert_viewer_reject(s->data); - ro_gui_dialog_close(s->window); - ro_gui_cert_release_window(s); + if (sslcert_viewer_keypress(certw->ssl_data, nskey)) { + return NSERROR_OK; } + return NSERROR_NOT_IMPLEMENTED; } + /** - * Callback to handle the closure of the SSL dialogue by other means. + * callback for mouse event on ro certificate viewer window * - * \param w The window being closed. + * \param ro_cw The ro core window structure. + * \param mouse_state mouse state + * \param x location of event + * \param y location of event + * \return NSERROR_OK on sucess otherwise apropriate error code. */ - -static void ro_gui_cert_close_window(wimp_w w) +static nserror +cert_mouse(struct ro_corewindow *ro_cw, + browser_mouse_state mouse_state, + int x, int y) { - struct ro_sslcert *s; + struct ro_cert_window *certw; + certw = (struct ro_cert_window *)ro_cw; - s = (struct ro_sslcert *) ro_gui_wimp_event_get_user_data(w); + sslcert_viewer_mouse_action(certw->ssl_data, mouse_state, x, y); - if (s != NULL) - ro_gui_cert_release_window(s); + return NSERROR_OK; } -/** - * Handle closing of the RISC OS certificate verification dialog, deleting - * the windows and freeing up the treeview and data block. - * - * \param *s The data block associated with the dialogue. - */ - -void ro_gui_cert_release_window(struct ro_sslcert *s) +/* exported interface documented in riscos/sslcert.h */ +nserror +gui_cert_verify(nsurl *url, + const struct ssl_cert_info *certs, + unsigned long num, + nserror (*cb)(bool proceed, void *pw), + void *cbpw) { os_error *error; + struct ro_cert_window *ncwin; /* new certificate window */ + nserror res; - if (s == NULL) - return; - - LOG("Releasing SSL data: 0x%x", (unsigned)s); + ncwin = malloc(sizeof(struct ro_cert_window)); + if (ncwin == NULL) { + return NSERROR_NOMEM; + } - ro_gui_wimp_event_finalise(s->window); - ro_treeview_destroy(s->tv); + /* initialise certificate viewing interface */ + res = sslcert_viewer_create_session_data(num, url, cb, cbpw, certs, + &ncwin->ssl_data); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } - error = xwimp_delete_window(s->window); + /* Create the SSL window */ + error = xwimp_create_window(dialog_cert_template, &ncwin->wh); if (error) { - LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); + LOG("xwimp_create_window: 0x%x: %s", + error->errnum, error->errmess); + free(ncwin); + return NSERROR_INIT_FAILED; } - error = xwimp_delete_window(s->pane); + + /* create ssl viewer pane window */ + error = xwimp_create_window(cert_tree_template, &ncwin->core.wh); if (error) { - LOG("xwimp_delete_window: 0x%x:%s", error->errnum, error->errmess); - ro_warn_user("WimpError", error->errmess); + LOG("xwimp_create_window: 0x%x: %s", + error->errnum, error->errmess); + free(ncwin); + return NSERROR_INIT_FAILED; + } + + /* setup callbacks */ + ncwin->core.draw = cert_draw; + ncwin->core.key = cert_key; + ncwin->core.mouse = cert_mouse; + + /* initialise core window */ + res = ro_corewindow_init(&ncwin->core, NULL, NULL, 0, NULL); + if (res != NSERROR_OK) { + free(ncwin); + return res; + } + + res = sslcert_viewer_init(ncwin->core.cb_table, + (struct core_window *)ncwin, + ncwin->ssl_data); + if (res != NSERROR_OK) { + free(ncwin); + return res; } - free(s); + /* Set up the certificate window event handling. + * + * (The action buttons are registered as button events, not OK and + * Cancel, as both need to carry out actions.) + */ + ro_gui_wimp_event_set_user_data(ncwin->wh, ncwin); + ro_gui_wimp_event_register_close_window(ncwin->wh, + ro_gui_cert_close_window); + ro_gui_wimp_event_register_button(ncwin->wh, + ICON_SSL_REJECT, + ro_gui_cert_reject); + ro_gui_wimp_event_register_button(ncwin->wh, + ICON_SSL_ACCEPT, + ro_gui_cert_accept); + + ro_gui_dialog_open_persistent(NULL, ncwin->wh, false); + + res = cert_attach_pane(ncwin->wh, ncwin->core.wh); + if (res != NSERROR_OK) { + ro_gui_cert_release_window(ncwin); + } + + return res; } + +/* exported interface documented in riscos/sslcert.h */ +void ro_gui_cert_initialise(void) +{ + /* Load template for the SSL certificate window */ + dialog_cert_template = ro_gui_dialog_load_template("sslcert"); + + /* load template for ssl treeview pane and adjust the window flags. */ + cert_tree_template = ro_gui_dialog_load_template("tree"); + + cert_tree_template->flags &= ~(wimp_WINDOW_MOVEABLE | + wimp_WINDOW_BACK_ICON | + wimp_WINDOW_CLOSE_ICON | + wimp_WINDOW_TITLE_ICON | + wimp_WINDOW_SIZE_ICON | + wimp_WINDOW_TOGGLE_ICON); +} diff --git a/frontends/riscos/sslcert.h b/frontends/riscos/sslcert.h index 17fce5552..09607f04c 100644 --- a/frontends/riscos/sslcert.h +++ b/frontends/riscos/sslcert.h @@ -17,18 +17,31 @@ * along with this program. If not, see . */ -/** \file - * SSL certificate viewer (interface). +/** + * \file + * RISC OS SSL certificate viewer interface. */ -#ifndef _NETSURF_RISCOS_SSLCERT_H_ -#define _NETSURF_RISCOS_SSLCERT_H_ +#ifndef NETSURF_RISCOS_SSLCERT_H +#define NETSURF_RISCOS_SSLCERT_H struct node; -void ro_gui_cert_preinitialise(void); -void ro_gui_cert_postinitialise(void); -void ro_gui_cert_open(struct tree *tree, struct node *node); +/** + * Load and initialise the certificate window template. + */ +void ro_gui_cert_initialise(void); + +/** + * Prompt the user to verify a certificate with issuse. + * + * \param url The URL being verified. + * \param certs The certificate to be verified + * \param num The number of certificates to be verified. + * \param cb Callback upon user decision. + * \param cbpw Context pointer passed to cb + */ +nserror gui_cert_verify(struct nsurl *url, const struct ssl_cert_info *certs, unsigned long num, nserror (*cb)(bool proceed, void *pw), void *cbpw); #endif -- cgit v1.2.3