Bill Gribble's patch.

* summary: separate the HTML and HTTP processing functions into
        different files to facilitate reuse.  Modularize much of the
        gnucash-specific behavior of the HTML code (<object> and form
        submission) to use run-time-expandable bahavior tables.  Add the
        gnc-action: mechanism for installing form submission handlers.

        * src/gnome/gng-gpg.c: initialize gnc-html handler for crypted
        HTML objects.  Remove all mention of GPG from gnc-html.c

        * src/gnome/gnc-html-actions.c: new file.  Add a simple form
        submission action (action=gnc-action:gnc-info/form?CGI_URL) to
        test submit and action processing.  This is useless ATM.  Some of
        the stuff in the privacy comments is unimplemented yet.

        * src/gnome/gnc-html-guppi.c: move all Guppi references from
        gnc-html.c into a separate file, with an initializer for
        the Guppi <object> tags.

        * src/gnome/gnc-html.c: get rid of SSL references; all that stuff
        is now in gnc-http.c.  Restructure to use gnc-http instead of
        ghttp directly.  Finish GET and POST default handlers, and add
        handler lookup/install mechanism for gnc-action: actions.  crib
        urlencoding function from gtkhtml guts.

        * src/gnome/gnc-http.c: new file.  Move HTTP stuff here. Finish
        POST handling.

        * src/gnome/top-level.c: add calls to Guppi, GPG, and gnc-html
        init functions.  These calls will eventually go into loadable
        module startup functions, when we get loadable modules.

        * src/scm/html-text.scm: Add html-markup/format.
        (html-markup/format "%a %a %a %a" 1 2 3 4) does what you'd expect,
        even if the non-format args are html-markup objects.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3759 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Dave Peticolas
2001-03-08 00:37:13 +00:00
parent 2a96c157c7
commit 9345e5cfa7
17 changed files with 1142 additions and 428 deletions

View File

@@ -1,3 +1,40 @@
2001-03-07 Bill Gribble <grib@billgribble.com>
* summary: separate the HTML and HTTP processing functions into
different files to facilitate reuse. Modularize much of the
gnucash-specific behavior of the HTML code (<object> and form
submission) to use run-time-expandable bahavior tables. Add the
gnc-action: mechanism for installing form submission handlers.
* src/gnome/gng-gpg.c: initialize gnc-html handler for crypted
HTML objects. Remove all mention of GPG from gnc-html.c
* src/gnome/gnc-html-actions.c: new file. Add a simple form
submission action (action=gnc-action:gnc-info/form?CGI_URL) to
test submit and action processing. This is useless ATM. Some of
the stuff in the privacy comments is unimplemented yet.
* src/gnome/gnc-html-guppi.c: move all Guppi references from
gnc-html.c into a separate file, with an initializer for
the Guppi <object> tags.
* src/gnome/gnc-html.c: get rid of SSL references; all that stuff
is now in gnc-http.c. Restructure to use gnc-http instead of
ghttp directly. Finish GET and POST default handlers, and add
handler lookup/install mechanism for gnc-action: actions. crib
urlencoding function from gtkhtml guts.
* src/gnome/gnc-http.c: new file. Move HTTP stuff here. Finish
POST handling.
* src/gnome/top-level.c: add calls to Guppi, GPG, and gnc-html
init functions. These calls will eventually go into loadable
module startup functions, when we get loadable modules.
* src/scm/html-text.scm: Add html-markup/format.
(html-markup/format "%a %a %a %a" 1 2 3 4) does what you'd expect,
even if the non-format args are html-markup objects.
2001-03-07 Dave Peticolas <dave@krondo.com>
* src/gnome/top-level.c (gnc_ui_check_events): add timeout

View File

@@ -34,9 +34,11 @@ libgncgnome_a_SOURCES = \
gnc-datedelta.c \
gnc-dateedit.c \
gnc-gpg.c \
gnc-html-embedded.c \
gnc-html-actions.c \
gnc-html-history.c \
gnc-html-guppi.c \
gnc-html.c \
gnc-http.c \
gnc-splash.c \
gtkselect.c \
mainwindow-account-tree.c \
@@ -89,9 +91,11 @@ noinst_HEADERS = \
gnc-datedelta.h \
gnc-dateedit.h \
gnc-gpg.h \
gnc-html-embedded.h \
gnc-html-actions.h \
gnc-html-history.h \
gnc-html-guppi.h \
gnc-html.h \
gnc-http.h \
gnc-splash.h \
gtkselect.h \
mainwindow-account-tree.h \

View File

@@ -23,13 +23,74 @@
#include "config.h"
#if USE_GPG
#include <sys/types.h>
#include <sys/stat.h>
#include <gnome.h>
#include <unistd.h>
#include "gnc-html.h"
#include "gnc-gpg.h"
static int handle_gpg_html(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
/********************************************************************
* gnc_gpg_init : called at startup time. adds a handler for crypted
* HTML to gnc-html.
********************************************************************/
void
gnc_gpg_init(void) {
gnc_html_register_object_handler("gnc-crypted-html", handle_gpg_html);
}
static char *
unescape_newlines(const gchar * in) {
const char * ip = in;
char * retval = g_strdup(in);
char * op = retval;
for(ip=in; *ip; ip++) {
if((*ip == '\\') && (*(ip+1)=='n')) {
*op = '\012';
op++;
ip++;
}
else {
*op = *ip;
op++;
}
}
*op = 0;
return retval;
}
/* we just want to take the data and stuff it into the gnc-html
* widget, blowing away the active streams. crypted-html contains a
* complete HTML page. */
static int
handle_gpg_html(gnc_html * html, GtkHTMLEmbedded * eb, gpointer data) {
int retval;
char * cryptext = unescape_newlines(eb->data);
char * cleartext = gnc_gpg_decrypt(cryptext, strlen(cryptext));
GtkHTMLStream * handle;
if(cleartext && cleartext[0]) {
handle = gtk_html_begin(html);
gtk_html_write(html, handle, cleartext, strlen(cleartext));
gtk_html_end(html, handle, GTK_HTML_STREAM_OK);
retval = TRUE;
}
else {
retval = FALSE;
}
g_free(cleartext);
g_free(cryptext);
return retval;
}
static char *
gnc_gpg_transform(const gchar * input, gint input_size,
char ** gpg_argv) {
@@ -206,3 +267,5 @@ gnc_gpg_make_keypair(const gchar * username,
gnc_gpg_transform(stdin, strlen(stdin), argv);
g_free(stdin);
}
#endif

View File

@@ -26,10 +26,11 @@
#include "config.h"
char * gnc_gpg_encrypt(const gchar * cleartext, int cleartext_size,
const gchar * recipient);
char * gnc_gpg_decrypt(const gchar * cleartext, int cleartext_size);
void gnc_gpg_make_keypair(const gchar * name, const gchar * id,
const gchar * email);
void gnc_gpg_init(void);
char * gnc_gpg_encrypt(const gchar * cleartext, int cleartext_size,
const gchar * recipient);
char * gnc_gpg_decrypt(const gchar * cleartext, int cleartext_size);
void gnc_gpg_make_keypair(const gchar * name, const gchar * id,
const gchar * email);
#endif

View File

@@ -0,0 +1,134 @@
/********************************************************************
* gnc-html-actions.c -- form submission actions *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
********************************************************************/
/********************************************************************
* THIS IS PRIVACY-SENSITIVE CODE. The actions handled here are run
* when gnucash needs to send HTML form information to a web server
* and can modify the information being sent or send additional
* information.
*
* Don't panic; all that means is that when an HTML form is loaded
* into the Gnucash HTML browser, after the user clicks the "submit"
* button, if the "action" in the form definition looks like
* "gnc-action:ACTION-NAME?ACTION-ARGS", the action-name is used to
* find a handler and the form is submitted by that handler. The
* default action handlers allow Gnucash to send information about
* itself along with a form, to send the form data in a GPG-encrypted
* block, etc. This is useful functionality, but there are real
* privacy concerns.
*
* Users: keep in mind that this is *not* a mechanism for executing
* arbitrary code in your gnucash; the only "actions" that can be
* taken must be compiled into the client, and you can disable them
* globally with a Preferences option.
*
* Developers: Until we have a formally-codified privacy policy,
* please follow these guidelines:
*
* 1. When actions send information that the user has not explicitly
* entered, there should *always* be a dialog or other notification,
* including the extra information to be sent, with an opportunity to
* bail out.
*
* 2. Do not use a accept a complete URI to submit to as an argument
* to actions. This might allow a malicious server to ask the
* gnucash client for private information to be sent to itself, if
* the user happened to go to that site from within the gnucash HTML
* browser and click a form "SUBMIT" button. Submit only to servers
* whose names the local user has specified as trusted servers for
* gnucash-related actions.
********************************************************************/
#include "config.h"
#include <string.h>
#include <glib.h>
#include "gnc-html-actions.h"
#include "gnc-html.h"
static int handle_gnc_info_form_submit(gnc_html * html, const char * method,
const char * action, const char * args,
const char * encoding);
/********************************************************************
* gnc_html_actions_init() : register the basic set of gnc-action:
* form submission actions.
********************************************************************/
void
gnc_html_actions_init(void) {
gnc_html_register_action_handler("gnc-info/form",
handle_gnc_info_form_submit);
}
/********************************************************************
* handle_gnc_info_form_submit() : submit the form arguments from
* 'encoding', appending additional arguments describing the gnucash
* client. this is justa test and doesn't submit any real
* information.
********************************************************************/
static int
handle_gnc_info_form_submit(gnc_html * html, const char * method,
const char * action, const char * args,
const char * encoding) {
char * extra_encoding = NULL;
char * new_encoding = NULL;
char * new_action = NULL;
char * msg_1 = gnc_html_encode_string("gnucash version 1.5");
char * msg_2 = gnc_html_encode_string("Hello, world");
if(!method || !action
|| strcmp(action, "gnc-info/form")) {
return FALSE;
}
extra_encoding = g_strconcat("gnc_version=", msg_1, "&"
"gnc_message=", msg_2, NULL);
if(encoding) {
new_encoding = g_strjoin("&", encoding, extra_encoding, NULL);
}
else {
new_encoding = extra_encoding;
extra_encoding = NULL;
}
new_action = g_strconcat("http://localhost/", args, NULL);
if(!strcasecmp(method, "get")) {
gnc_html_generic_get_submit(html, new_action, new_encoding);
}
else {
gnc_html_generic_post_submit(html, new_action, new_encoding);
}
g_free(extra_encoding);
g_free(new_encoding);
g_free(new_action);
g_free(msg_1);
g_free(msg_2);
return TRUE;
}

View File

@@ -0,0 +1,30 @@
/********************************************************************
* gnc-html-actions.h -- basic form submission actions *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
\********************************************************************/
#ifndef __GNC_HTML_ACTIONS_H__
#define __GNC_HTML_ACTIONS_H__
#include "gnc-html.h"
void gnc_html_actions_init(void);
#endif

View File

@@ -1,5 +1,5 @@
/********************************************************************
* gnc-html-embedded.c -- embed objects in the html stream. *
* gnc-html-guppi.c -- embed guppi objects in the html stream. *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
@@ -22,16 +22,96 @@
#include "config.h"
#ifdef USE_GUPPI
#include <gnome.h>
#include <glib.h>
#include <guile/gh.h>
#include <gtkhtml/gtkhtml.h>
#include <gtkhtml/gtkhtml-embedded.h>
#ifdef USE_GUPPI
#include <libguppitank/guppi-tank.h>
#endif
#include "gnc-html.h"
#include "gnc-html-guppi.h"
#include "gnc-html-embedded.h"
#include "mainwindow-account-tree.h"
static int handle_piechart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
static int handle_barchart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
static int handle_scatter(gnc_html * html, GtkHTMLEmbedded * eb, gpointer d);
/********************************************************************
* gnc_html_guppi_init
* add object handlers for guppi objects
********************************************************************/
void
gnc_html_guppi_init(void) {
guppi_tank_init();
gnc_html_register_object_handler("gnc-guppi-pie", handle_piechart);
gnc_html_register_object_handler("gnc-guppi-bar", handle_barchart);
gnc_html_register_object_handler("gnc-guppi-scatter", handle_scatter);
}
/* the handlers for pie. bar, and scatter charts */
static int
handle_piechart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer data) {
GtkWidget * widg = NULL;
int retval;
widg = gnc_html_embedded_piechart(html, eb->width, eb->height,
eb->params);
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
return retval;
}
static int
handle_barchart(gnc_html * html, GtkHTMLEmbedded * eb, gpointer data) {
GtkWidget * widg = NULL;
int retval;
widg = gnc_html_embedded_barchart(html, eb->width, eb->height,
eb->params);
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
return retval;
}
static int
handle_scatter(gnc_html * html, GtkHTMLEmbedded * eb, gpointer data) {
GtkWidget * widg = NULL;
int retval;
widg = gnc_html_embedded_scatter(html, eb->width, eb->height,
eb->params);
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
return retval;
}
/********************************************************************
* now we start the actual embedded object creation routines. well,
* after some utilities.
********************************************************************/
static double *
read_doubles(const char * string, int nvalues) {
@@ -102,8 +182,6 @@ free_strings(char ** strings, int nstrings) {
}
#ifdef USE_GUPPI
struct guppi_chart_data {
GtkWidget * widget;
GuppiObject * guppiobject;
@@ -725,7 +803,6 @@ gnc_html_embedded_scatter(gnc_html * parent,
return NULL;
}
#endif /* USE_GUPPI */
/********************************************************************
* gnc_html_embedded_account_tree
@@ -751,26 +828,4 @@ set_bools(char * indices, gboolean * array, int num) {
}
GtkWidget *
gnc_html_embedded_account_tree(gnc_html * parent,
int w, int h, GHashTable * params) {
AccountViewInfo info;
GtkWidget * tree = gnc_mainwin_account_tree_new();
char * param;
int * fields;
memset(&info, 0, sizeof(AccountViewInfo));
if((param = g_hash_table_lookup(params, "fields"))) {
set_bools(param, &(info.show_field[0]), NUM_ACCOUNT_FIELDS);
}
if((param = g_hash_table_lookup(params, "types"))) {
set_bools(param, &(info.include_type[0]), NUM_ACCOUNT_TYPES);
}
gnc_mainwin_account_tree_set_view_info(GNC_MAINWIN_ACCOUNT_TREE(tree),
info);
gnc_account_tree_refresh(GNC_ACCOUNT_TREE
(GNC_MAINWIN_ACCOUNT_TREE(tree)->acc_tree));
return tree;
}
#endif

View File

@@ -1,5 +1,5 @@
/********************************************************************
* gnc-html-embedded.h -- embed objects in the html stream *
* gnc-html-guppi.h -- embed objects in the html stream *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
@@ -20,12 +20,13 @@
* Boston, MA 02111-1307, USA gnu@gnu.org *
\********************************************************************/
#ifndef __GNC_HTML_EMBEDDED_H__
#define __GNC_HTML_EMBEDDED_H__
#ifndef __GNC_HTML_GUPPI_H__
#define __GNC_HTML_GUPPI_H__
#include <gnome.h>
#include "gnc-html.h"
void gnc_html_guppi_init(void);
GtkWidget * gnc_html_embedded_piechart(gnc_html * parent,
gint w, gint h, GHashTable * params);
GtkWidget * gnc_html_embedded_barchart(gnc_html * parent,

View File

@@ -23,6 +23,7 @@
#include "config.h"
#include <glib.h>
#include <string.h>
#include "gnc-html-history.h"
@@ -41,7 +42,7 @@ struct _gnc_html_history {
********************************************************************/
gnc_html_history *
gnc_html_history_new() {
gnc_html_history_new(void) {
gnc_html_history * hist = g_new0(gnc_html_history, 1);
hist->nodes = NULL;
hist->current_node = NULL;

View File

@@ -32,16 +32,6 @@
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <ghttp_ssl.h>
#endif
#include <ghttp.h>
#include <gtkhtml/gtkhtml.h>
#include <gtkhtml/gtkhtml-embedded.h>
#ifdef USE_GUPPI
@@ -64,29 +54,30 @@
#include "gnc-engine-util.h"
#include "gnc-gpg.h"
#include "gnc-html.h"
#include "gnc-html-actions.h"
#include "gnc-http.h"
#include "gnc-html-history.h"
#include "gnc-html-embedded.h"
#include "query-user.h"
#include "window-help.h"
#include "window-report.h"
struct _gnc_html {
GtkWidget * container;
GtkWidget * html;
GtkWidget * container; /* parent of the gtkhtml widget */
GtkWidget * html; /* gtkhtml widget itself */
gchar * current_link; /* link under mouse pointer */
gchar * current_link; /* link under mouse pointer */
URLType base_type; /* base of URL (path - filename) */
gchar * base_location;
URLType base_type; /* base of URL (path - filename) */
gchar * base_location;
gnc_http * http; /* handles HTTP requests */
GHashTable * request_info; /* hash uri to GList of GtkHTMLStream * */
/* callbacks */
GncHTMLUrltypeCB urltype_cb;
GncHTMLUrltypeCB urltype_cb; /* is this type OK for this instance? */
GncHTMLLoadCB load_cb;
GncHTMLFlyoverCB flyover_cb;
GncHTMLButtonCB button_cb;
GList * requests; /* outstanding ghttp requests */
gpointer flyover_cb_data;
gpointer load_cb_data;
gpointer button_cb_data;
@@ -94,15 +85,18 @@ struct _gnc_html {
struct _gnc_html_history * history;
};
struct request_info {
gchar * uri;
ghttp_request * request;
GtkHTMLStream * handle;
};
/* This static indicates the debugging module that this .o belongs to. */
/* indicates the debugging module that this .o belongs to. */
static short module = MOD_HTML;
/* hashes an HTML <object classid="ID"> classid to a handler function */
static GHashTable * gnc_html_object_handlers = NULL;
/* hashes an action name from a FORM definition to a handler function.
* <form method=METHOD action=gnc-action:ACTION-NAME?ACTION-ARGS>
* action-args is what gets passed to the handler. */
static GHashTable * gnc_html_action_handlers = NULL;
static char error_404[] =
"<html><body><h3>Not found</h3><p>The specified URL could not be loaded.</body></html>";
@@ -170,6 +164,9 @@ gnc_html_parse_url(gnc_html * html, const gchar * url,
else if(!strcmp(protocol, "https")) {
retval = URL_TYPE_SECURE;
}
else if(!strcmp(protocol, "gnc-action")) {
retval = URL_TYPE_ACTION;
}
else if(!strcmp(protocol, "gnc-register")) {
retval = URL_TYPE_REGISTER;
}
@@ -326,152 +323,100 @@ rebuild_url(URLType type, const gchar * location, const gchar * label) {
}
}
static guint ghttp_callback_tag = 0;
static int ghttp_callback_enabled = FALSE;
/************************************************************
* gnc_html_http_request_cb: fires when an HTTP request is completed.
* this is when it's time to load the data into the GtkHTML widget.
************************************************************/
static gint
ghttp_check_callback(gpointer data) {
gnc_html * html = data;
GList * current;
ghttp_status status;
struct request_info * req;
URLType type;
char * location = NULL;
char * label = NULL;
/* walk the request list to deal with any complete requests */
for(current = html->requests; current; current = current->next) {
req = current->data;
status = ghttp_process(req->request);
switch(status) {
case ghttp_done:
if (ghttp_get_body_len(req->request) > 0) {
{
/* hack alert FIXME:
* This code tries to see if the returned body is
* in fact gnc xml code. If it seems to be, then we
* load it as data, rather than loading it into the
* gtkhtml widget. My gut impression is that we should
* probably be doing this somewhere else, some other
* way, not here .... But I can't think of anything
* better for now. -- linas
*/
const char * bufp = ghttp_get_body(req->request);
bufp += strspn (bufp, " /t/v/f/n/r");
if (!strncmp (bufp, "<?xml version", 13)) {
gncFileOpenFile ((char *) req->uri);
return TRUE;
}
}
gtk_html_write(GTK_HTML(html->html),
req->handle,
ghttp_get_body(req->request),
ghttp_get_body_len(req->request));
gtk_html_end(GTK_HTML(html->html), req->handle, GTK_HTML_STREAM_OK);
static void
gnc_html_http_request_cb(const gchar * uri, int completed_ok,
const gchar * body, gint body_len,
gpointer user_data) {
gnc_html * html = user_data;
URLType type;
char * location = NULL;
char * label = NULL;
GList * handles;
GList * current;
type = gnc_html_parse_url(html, req->uri, &location, &label);
handles = g_hash_table_lookup(html->request_info, uri);
/* handles will be NULL for an HTTP POST transaction, where we are
* displaying the reply data. */
if(!handles) {
GtkHTMLStream * handle = gtk_html_begin(GTK_HTML(html->html));
gtk_html_write(GTK_HTML(html->html), handle, body, body_len);
gtk_html_end(GTK_HTML(html->html), handle, GTK_HTML_STREAM_OK);
}
/* otherwise, it's a normal SUBMIT transaction */
else {
for(current = handles; current; current = current->next) {
/* request completed OK... write the HTML to the handles that
* asked for that URI. */
if(completed_ok) {
gtk_html_write(GTK_HTML(html->html), (GtkHTMLStream *)(current->data),
body, body_len);
gtk_html_end(GTK_HTML(html->html), (GtkHTMLStream *)(current->data),
GTK_HTML_STREAM_OK);
type = gnc_html_parse_url(html, uri, &location, &label);
if(label) {
gtk_html_jump_to_anchor(GTK_HTML(html->html), label);
}
g_free(location);
g_free(label);
location = label = NULL;
}
/* request failed... body is the ghttp error text. */
else {
gtk_html_write(GTK_HTML(html->html), req->handle, error_404,
strlen(error_404));
gtk_html_end(GTK_HTML(html->html), req->handle, GTK_HTML_STREAM_ERROR);
gtk_html_write(GTK_HTML(html->html), (GtkHTMLStream *)(current->data),
error_start, strlen(error_start));
gtk_html_write(GTK_HTML(html->html), (GtkHTMLStream *)(current->data),
body, body_len);
gtk_html_write(GTK_HTML(html->html), (GtkHTMLStream *)(current->data),
error_end, strlen(error_end));
gtk_html_end(GTK_HTML(html->html), (GtkHTMLStream *)(current->data),
GTK_HTML_STREAM_ERROR);
}
ghttp_request_destroy(req->request);
req->request = NULL;
req->handle = NULL;
current->data = NULL;
g_free(req);
break;
case ghttp_error:
gtk_html_write(GTK_HTML(html->html), req->handle, error_start,
strlen(error_start));
gtk_html_write(GTK_HTML(html->html), req->handle,
ghttp_get_error(req->request),
strlen(ghttp_get_error(req->request)));
gtk_html_write(GTK_HTML(html->html), req->handle, error_end,
strlen(error_end));
gtk_html_end(GTK_HTML(html->html), req->handle, GTK_HTML_STREAM_ERROR);
ghttp_request_destroy(req->request);
req->request = NULL;
req->handle = NULL;
current->data = NULL;
g_free(req);
break;
case ghttp_not_done:
break;
}
}
/* walk the list again to remove dead requests */
current = html->requests;
while(current) {
if(current->data == NULL) {
html->requests = g_list_remove_link(html->requests, current);
current = html->requests;
/* now clean up the request info from the hash table */
handles = NULL;
if(g_hash_table_lookup_extended(html->request_info, uri,
(gpointer *)&location,
(gpointer *)&handles)) {
/* free the URI and the list of handles */
g_free(location);
g_list_free(handles);
g_hash_table_remove(html->request_info, uri);
}
else {
current = current->next;
}
}
/* if all requests are done, disable the timeout */
if(html->requests == NULL) {
ghttp_callback_enabled = FALSE;
ghttp_callback_tag = 0;
return FALSE;
}
else {
return TRUE;
}
}
#ifdef HAVE_OPENSSL
static int
gnc_html_certificate_check_cb(ghttp_request * req, X509 * cert,
void * user_data) {
PINFO("checking SSL certificate...");
X509_print_fp(stdout, cert);
PINFO(" ... done\n");
return TRUE;
}
#endif
/************************************************************
* gnc_html_start_request: starts the gnc-http object working on an
* http/https request.
************************************************************/
static void
gnc_html_start_request(gnc_html * html, gchar * uri, GtkHTMLStream * handle) {
struct request_info * info = g_new0(struct request_info, 1);
GList * handles = NULL;
gint need_request = FALSE;
info->request = ghttp_request_new();
info->handle = handle;
info->uri = g_strdup (uri);
#ifdef HAVE_OPENSSL
ghttp_enable_ssl(info->request);
ghttp_set_ssl_certificate_callback(info->request,
gnc_html_certificate_check_cb,
(void *)html);
#endif
ghttp_set_uri(info->request, uri);
ghttp_set_header(info->request, http_hdr_User_Agent,
"gnucash/1.5 (Financial Browser for Linux; http://gnucash.org)");
ghttp_set_sync(info->request, ghttp_async);
ghttp_prepare(info->request);
ghttp_process(info->request);
/* we want to make a list of handles to fill with this URI.
* multiple handles with the same URI will all get filled when the
* request comes in. */
handles = g_hash_table_lookup(html->request_info, uri);
if(!handles) {
need_request = TRUE;
}
html->requests = g_list_append(html->requests, info);
handles = g_list_append(handles, handle);
g_hash_table_insert(html->request_info, uri, handles);
/* start the gtk timeout if not started */
if(!ghttp_callback_enabled) {
ghttp_callback_tag =
gtk_timeout_add(100, ghttp_check_callback, (gpointer)html);
ghttp_callback_enabled = TRUE;
if(need_request) {
gnc_http_start_request(html->http, uri, gnc_html_http_request_cb,
(gpointer)html);
}
}
@@ -633,27 +578,6 @@ gnc_html_guppi_redraw_cb(GtkHTMLEmbedded * eb,
}
#endif /* USE_GUPPI */
static char *
unescape_newlines(const gchar * in) {
const char * ip = in;
char * retval = g_strdup(in);
char * op = retval;
for(ip=in; *ip; ip++) {
if((*ip == '\\') && (*(ip+1)=='n')) {
*op = '\012';
op++;
ip++;
}
else {
*op = *ip;
op++;
}
}
*op = 0;
return retval;
}
/********************************************************************
* gnc_html_object_requested_cb - called when an applet needs to be
@@ -666,100 +590,17 @@ gnc_html_object_requested_cb(GtkHTML * html, GtkHTMLEmbedded * eb,
GtkWidget * widg = NULL;
gnc_html * gnchtml = data;
int retval = FALSE;
GncHTMLObjectCB h;
if(!strcmp(eb->classid, "gnc-guppi-pie")) {
#ifdef USE_GUPPI
widg = gnc_html_embedded_piechart(gnchtml, eb->width, eb->height,
eb->params);
#endif /* USE_GUPPI */
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
if(!eb || !(eb->classid) || !gnc_html_object_handlers) return FALSE;
h = g_hash_table_lookup(gnc_html_object_handlers, eb->classid);
if(h) {
return h(gnchtml, eb, data);
}
else if(!strcmp(eb->classid, "gnc-guppi-bar")) {
#ifdef USE_GUPPI
widg = gnc_html_embedded_barchart(gnchtml, eb->width, eb->height,
eb->params);
#endif /* USE_GUPPI */
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
else {
return FALSE;
}
else if(!strcmp(eb->classid, "gnc-guppi-scatter")) {
#ifdef USE_GUPPI
widg = gnc_html_embedded_scatter(gnchtml, eb->width, eb->height,
eb->params);
#endif /* USE_GUPPI */
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
}
else if(!strcmp(eb->classid, "gnc-account-tree")) {
widg = gnc_html_embedded_account_tree(gnchtml, eb->width, eb->height,
eb->params);
if(widg) {
gtk_widget_show_all(widg);
gtk_container_add(GTK_CONTAINER(eb), widg);
gtk_widget_set_usize(GTK_WIDGET(eb), eb->width, eb->height);
retval = TRUE;
}
else {
retval = FALSE;
}
}
#if USE_GPG
else if(!strcmp(eb->classid, "gnc-crypted-html")) {
/* we just want to take the data and stuff it into the widget,
blowing away the active streams. crypted-html contains a
complete HTML page. */
char * cryptext = unescape_newlines(eb->data);
char * cleartext = gnc_gpg_decrypt(cryptext, strlen(cryptext));
GtkHTMLStream * handle;
if(cleartext && cleartext[0]) {
handle = gtk_html_begin(html);
gtk_html_write(html, handle, cleartext, strlen(cleartext));
gtk_html_end(html, handle, GTK_HTML_STREAM_OK);
retval = TRUE;
}
else {
retval = FALSE;
}
g_free(cleartext);
g_free(cryptext);
}
#endif /* USE_GPG */
#if 0 && defined(USE_GUPPI)
if(widg) {
gtk_signal_connect(GTK_OBJECT(eb), "draw_gdk",
GTK_SIGNAL_FUNC(gnc_html_guppi_redraw_cb),
widg);
gtk_signal_connect(GTK_OBJECT(eb), "draw_print",
GTK_SIGNAL_FUNC(gnc_html_guppi_print_cb),
widg);
}
#endif
return retval;
}
@@ -896,14 +737,41 @@ static int
gnc_html_submit_cb(GtkHTML * html, const gchar * method,
const gchar * action, const gchar * encoding,
gpointer user_data) {
if(!strcasecmp(method, "get")) {
PINFO("GET submit: m='%s', a='%s', e='%s'",
method, action, encoding);
gnc_html * gnchtml = user_data;
char * location = NULL;
char * new_loc = NULL;
char * label = NULL;
char * submit_encoding = NULL;
char ** action_parts;
URLType type;
GncHTMLActionCB cb;
type = gnc_html_parse_url(gnchtml, action, &location, &label);
if(type == URL_TYPE_ACTION) {
if(gnc_html_action_handlers) {
action_parts = g_strsplit(location, "?", 2);
if(action_parts && action_parts[0]) {
cb = g_hash_table_lookup(gnc_html_action_handlers, action_parts[0]);
cb(gnchtml, method, action_parts[0], action_parts[1], encoding);
}
else {
printf("tried to split on ? but failed...\n");
}
}
}
else if(!strcasecmp(method, "post")) {
PINFO("POST submit: m='%s', a='%s', e='%s'",
method, action, encoding);
else {
if(!strcasecmp(method, "get")) {
gnc_html_generic_get_submit(gnchtml, action, encoding);
}
else if(!strcasecmp(method, "post")) {
gnc_html_generic_post_submit(gnchtml, action, encoding);
}
}
g_free(location);
g_free(label);
g_free(new_loc);
return TRUE;
}
@@ -941,7 +809,7 @@ static void
gnc_html_open_report(gnc_html * html, const gchar * location,
const gchar * label, int newwin) {
gnc_report_window * rwin;
GtkHTMLStream * stream;
GtkHTMLStream * handle;
/* make a new window if necessary */
if(newwin) {
@@ -957,8 +825,8 @@ gnc_html_open_report(gnc_html * html, const gchar * location,
html->base_type = URL_TYPE_FILE;
html->base_location = NULL;
stream = gtk_html_begin(GTK_HTML(html->html));
gnc_html_load_to_stream(html, stream, URL_TYPE_REPORT, location, label);
handle = gtk_html_begin(GTK_HTML(html->html));
gnc_html_load_to_stream(html, handle, URL_TYPE_REPORT, location, label);
}
@@ -1006,7 +874,7 @@ void
gnc_html_show_url(gnc_html * html, URLType type,
const gchar * location, const gchar * label,
int newwin_hint) {
GtkHTMLStream * handle;
int newwin;
@@ -1080,17 +948,17 @@ gnc_html_reload(gnc_html * html) {
}
/********************************************************************\
/********************************************************************
* gnc_html_new
* create and set up a new gtkhtml widget.
\********************************************************************/
********************************************************************/
gnc_html *
gnc_html_new(void) {
gnc_html * retval = g_new0(gnc_html, 1);
retval->container = gtk_scrolled_window_new(NULL, NULL);
retval->html = gtk_html_new();
retval->html = gtk_html_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(retval->container),
GTK_POLICY_AUTOMATIC,
@@ -1098,8 +966,10 @@ gnc_html_new(void) {
gtk_container_add(GTK_CONTAINER(retval->container),
GTK_WIDGET(retval->html));
retval->history = gnc_html_history_new();
retval->request_info = g_hash_table_new(g_str_hash, g_str_equal);
retval->http = gnc_http_new();
retval->history = gnc_html_history_new();
gtk_widget_ref (retval->container);
gtk_object_sink (GTK_OBJECT (retval->container));
@@ -1142,41 +1012,22 @@ gnc_html_new(void) {
return retval;
}
/********************************************************************\
/********************************************************************
* gnc_html_cancel
* cancel any outstanding HTML fetch requests.
\********************************************************************/
********************************************************************/
void
gnc_html_cancel(gnc_html * html) {
GList * current;
if(ghttp_callback_enabled == TRUE) {
gtk_timeout_remove(ghttp_callback_tag);
ghttp_callback_enabled = FALSE;
ghttp_callback_tag = 0;
/* go through and destroy all the requests */
for(current = html->requests; current; current = current->next) {
if(current->data) {
struct request_info * r = current->data;
ghttp_request_destroy(r->request);
g_free(r->uri);
g_free(r);
current->data = NULL;
}
}
/* free the list backbone */
g_list_free(html->requests);
html->requests = NULL;
}
gnc_http_cancel_requests(html->http);
}
/********************************************************************\
/********************************************************************
* gnc_html_destroy
* destroy the struct
\********************************************************************/
********************************************************************/
void
gnc_html_destroy(gnc_html * html) {
@@ -1229,44 +1080,41 @@ gnc_html_set_button_cb(gnc_html * html, GncHTMLButtonCB button_cb,
html->button_cb_data = data;
}
/* ------------------------------------------------------- */
/**************************************************************
* gnc_html_export : wrapper around the builtin function in gtkhtml
**************************************************************/
static gboolean
raw_html_receiver (gpointer engine,
const gchar *data,
guint len,
gpointer user_data)
{
const gchar *data,
guint len,
gpointer user_data) {
FILE *fh = (FILE *) user_data;
fwrite (data, len, 1, fh);
return TRUE;
}
void
gnc_html_export(gnc_html * html)
{
gnc_html_export(gnc_html * html) {
const char *filepath;
FILE *fh;
filepath = fileBox (_("Save HTML To File"), NULL, NULL);
PINFO (" user selected file=%s\n", filepath);
fh = fopen (filepath, "w");
if (NULL == fh)
{
const char *fmt = _("Could not open the file\n"
" %s\n%s");
char *buf = g_strdup_printf (fmt, filepath, strerror (errno));
gnc_error_dialog (buf);
if (buf) g_free (buf);
return;
if (NULL == fh) {
const char *fmt = _("Could not open the file\n"
" %s\n%s");
char *buf = g_strdup_printf (fmt, filepath, strerror (errno));
gnc_error_dialog (buf);
if (buf) g_free (buf);
return;
}
gtk_html_save (GTK_HTML(html->html), raw_html_receiver, fh);
fclose (fh);
}
/* ------------------------------------------------------- */
void
gnc_html_print(gnc_html * html) {
PrintSession * ps = gnc_print_session_create();
@@ -1290,29 +1138,197 @@ gnc_html_get_widget(gnc_html * html) {
return html->container;
}
#ifdef _TEST_GNC_HTML_
int
main(int argc, char ** argv) {
GtkWidget * wind;
gnc_html * html;
gnome_init("test", "1.0", argc, argv);
gdk_rgb_init();
gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
gtk_widget_set_default_visual (gdk_rgb_get_visual ());
wind = gtk_window_new(GTK_WINDOW_TOPLEVEL);
html = gnc_html_new();
gtk_container_add(GTK_CONTAINER(wind), GTK_WIDGET(html->container));
gtk_widget_show_all(wind);
gnc_html_load_file(html, "test.html");
gtk_main();
void
gnc_html_register_object_handler(const char * classid,
GncHTMLObjectCB hand) {
if(!gnc_html_object_handlers) {
gnc_html_object_handlers = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_insert(gnc_html_object_handlers, g_strdup(classid), hand);
}
#endif
void
gnc_html_unregister_object_handler(const char * classid) {
gchar * keyptr=NULL;
gchar * valptr=NULL;
g_hash_table_lookup_extended(gnc_html_object_handlers,
classid,
(gpointer *)&keyptr,
(gpointer *)&valptr);
if(keyptr) {
g_free(keyptr);
g_hash_table_remove(gnc_html_object_handlers, classid);
}
}
void
gnc_html_register_action_handler(const char * actionid,
GncHTMLActionCB hand) {
if(!gnc_html_action_handlers) {
gnc_html_action_handlers = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_insert(gnc_html_action_handlers, g_strdup(actionid), hand);
}
void
gnc_html_unregister_action_handler(const char * actionid) {
gchar * keyptr=NULL;
gchar * valptr=NULL;
g_hash_table_lookup_extended(gnc_html_action_handlers,
actionid,
(gpointer *)&keyptr,
(gpointer *)&valptr);
if(keyptr) {
g_free(keyptr);
g_hash_table_remove(gnc_html_action_handlers, actionid);
}
}
/********************************************************************
* gnc_html_encode_string
* RFC 1738 encoding of string for submission with an HTML form.
* GPL code lifted from gtkhtml. copyright notice:
*
* Copyright (C) 1997 Martin Jones (mjones@kde.org)
* Copyright (C) 1997 Torben Weis (weis@kde.org)
* Copyright (C) 1999 Helix Code, Inc.
********************************************************************/
char *
gnc_html_encode_string(const char * str) {
static gchar *safe = "$-._!*(),"; /* RFC 1738 */
unsigned pos = 0;
GString *encoded = g_string_new ("");
gchar buffer[5], *ptr;
guchar c;
while(pos < strlen(str)) {
c = (unsigned char) str[pos];
if ((( c >= 'A') && ( c <= 'Z')) ||
(( c >= 'a') && ( c <= 'z')) ||
(( c >= '0') && ( c <= '9')) ||
(strchr(safe, c))) {
encoded = g_string_append_c (encoded, c);
}
else if ( c == ' ' ) {
encoded = g_string_append_c (encoded, '+');
}
else if ( c == '\n' ) {
encoded = g_string_append (encoded, "%0D%0A");
}
else if ( c != '\r' ) {
sprintf( buffer, "%%%02X", (int)c );
encoded = g_string_append (encoded, buffer);
}
pos++;
}
ptr = encoded->str;
g_string_free (encoded, FALSE);
return (char *)ptr;
}
/********************************************************************
* gnc_html_generic_get_submit() : normal 'get' submit method.
********************************************************************/
void
gnc_html_generic_get_submit(gnc_html * html, const char * action,
const char * encoding) {
URLType type;
char * location = NULL;
char * label = NULL;
char * fullurl = NULL;
type = gnc_html_parse_url(html, action, &location, &label);
fullurl = g_strconcat(location, "?", encoding, NULL);
gnc_html_show_url(html, type, fullurl, label, 0);
g_free(location);
g_free(label);
g_free(fullurl);
}
/********************************************************************
* gnc_html_generic_post_submit() : normal 'post' submit method.
********************************************************************/
void
gnc_html_generic_post_submit(gnc_html * html, const char * action,
const char * encoding) {
char * htmlstr = g_strconcat(encoding,
"&submit=submit",
NULL);
gnc_http_start_post(html->http, action,
"application/x-www-form-urlencoded",
htmlstr, strlen(htmlstr),
gnc_html_http_request_cb, html);
}
/********************************************************************
* gnc_html_multipart_post_submit() : this is really sort of useless
* but I'll make it better later. It's useless because FTMP CGI/php
* don't properly decode the urlencoded values.
********************************************************************/
void
gnc_html_multipart_post_submit(gnc_html * html, const char * action,
const char * encoding) {
char * htmlstr = g_strdup("");
char * next_htmlstr;
char * next_pair = g_strconcat(encoding, "&submit=submit", NULL);
char * name = NULL;
char * value = NULL;
char * extr_name = NULL;
char * extr_value = NULL;
char * length_line = NULL;
while(next_pair) {
name = next_pair;
if((value = strchr(name, '='))) {
extr_name = g_strndup(name, value-name);
next_pair = strchr(value, '&');
if(next_pair) {
extr_value = g_strndup(value+1, next_pair-value-1);
next_pair++;
}
else {
extr_value = g_strdup(value+1);
}
next_htmlstr =
g_strconcat(htmlstr,
"--XXXgncXXX\r\n",
"Content-Disposition: form-data; name=\"",
extr_name, "\"\r\n",
"Content-Type: application/x-www-form-urlencoded\r\n\r\n",
extr_value, "\r\n",
NULL);
g_free(htmlstr);
htmlstr = next_htmlstr;
next_htmlstr = NULL;
}
else {
next_pair = NULL;
}
}
next_htmlstr = g_strconcat(htmlstr, "--XXXgncXXX--\r\n", NULL);
g_free(htmlstr);
htmlstr = next_htmlstr;
next_htmlstr = NULL;
gnc_http_start_post(html->http, action,
"multipart/form-data; boundary=XXXgncXXX",
htmlstr, strlen(htmlstr),
gnc_html_http_request_cb, html);
g_free(htmlstr);
}

View File

@@ -1,5 +1,5 @@
/********************************************************************\
* gnc-html.h -- display html with gnc special tags
/********************************************************************
* gnc-html.h -- display html with gnc special tags *
* Copyright (C) 2000 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
@@ -23,15 +23,10 @@
#ifndef __GNC_HTML_H__
#define __GNC_HTML_H__
#include <gnome.h>
#include <ghttp.h>
#include <glib.h>
#include <gtkhtml/gtkhtml.h>
/*
* The gnc_html_export() routine will export the html displayed to a
* file. It will pop up a file dialog box to ask user for a
* filename.
*/
#include <gdk/gdk.h>
#include <gtk/gtk.h>
typedef enum { URL_TYPE_FILE, URL_TYPE_JUMP,
URL_TYPE_HTTP, URL_TYPE_FTP,
@@ -40,13 +35,15 @@ typedef enum { URL_TYPE_FILE, URL_TYPE_JUMP,
URL_TYPE_REPORT, /* for gnucash report popups */
URL_TYPE_SCHEME, /* for scheme code evaluation */
URL_TYPE_HELP, /* for a gnucash help window */
URL_TYPE_XMLDATA, /* links to gnucash XML data files */
URL_TYPE_ACTION, /* for special SUBMIT actions */
URL_TYPE_OTHER } URLType;
#include "gnc-html-history.h"
typedef struct _gnc_html gnc_html;
typedef int (*GncHTMLUrltypeCB)(URLType ut);
typedef int (* GncHTMLUrltypeCB)(URLType ut);
typedef void (* GncHTMLFlyoverCB)(gnc_html * html, const char * url,
gpointer data);
typedef void (* GncHTMLLoadCB)(gnc_html * html, URLType type,
@@ -54,7 +51,11 @@ typedef void (* GncHTMLLoadCB)(gnc_html * html, URLType type,
gpointer data);
typedef int (* GncHTMLButtonCB)(gnc_html * html, GdkEventButton * event,
gpointer data);
typedef int (* GncHTMLObjectCB)(gnc_html * html, GtkHTMLEmbedded * eb,
gpointer data);
typedef int (* GncHTMLActionCB)(gnc_html * html, const char * method,
const char * action, const char * act_args,
const char * encoding);
gnc_html * gnc_html_new(void);
void gnc_html_destroy(gnc_html * html);
void gnc_html_show_url(gnc_html * html,
@@ -65,9 +66,32 @@ void gnc_html_export(gnc_html * html);
void gnc_html_print(gnc_html * html);
void gnc_html_cancel(gnc_html * html);
URLType
gnc_html_parse_url(gnc_html * html, const gchar * url,
char ** url_location, char ** url_label);
/* object handlers deal with <object classid="foo"> objects in HTML.
* the handlers are looked up at object load time. */
void gnc_html_register_object_handler(const char * classid,
GncHTMLObjectCB hand);
void gnc_html_unregister_object_handler(const char * classid);
/* action handlers deal with submitting forms of the type
* <FORM action="gnc-action:action?args">. Normal get/post http:
* forms are handled as would be expected, with no callback. */
void gnc_html_register_action_handler(const char * action,
GncHTMLActionCB hand);
void gnc_html_unregister_action_handler(const char * action);
/* default action handlers for GET and POST methods. 'generic_post'
* is the trivial application/x-www-form-urlencoded submit,
* multipart-post is a multipart/form-data submit. */
void gnc_html_generic_get_submit(gnc_html * html, const char * act,
const char * encoding);
void gnc_html_generic_post_submit(gnc_html * html, const char * act,
const char * encoding);
void gnc_html_multipart_post_submit(gnc_html * html, const char * a,
const char * encoding);
URLType gnc_html_parse_url(gnc_html * html, const gchar * url,
char ** url_location, char ** url_label);
char * gnc_html_encode_string(const char * in);
gnc_html_history * gnc_html_get_history(gnc_html * html);
GtkWidget * gnc_html_get_widget(gnc_html * html);

249
src/gnome/gnc-http.c Normal file
View File

@@ -0,0 +1,249 @@
/********************************************************************
* gnc-http.c -- handle processing of HTTP requests via gnome-http *
* Copyright (C) 2001 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
********************************************************************/
#include "config.h"
#ifdef HAVE_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <ghttp_ssl.h>
#endif
#include <ghttp.h>
#include <glib.h>
#include <gtk/gtkmain.h>
#include <string.h>
#include "gnc-http.h"
struct _gnc_http {
GList * requests;
guint callback_tag;
gint callback_enabled;
};
struct request_info {
gchar * uri;
ghttp_request * request;
GncHTTPRequestCB callback;
gpointer callback_data;
};
gnc_http *
gnc_http_new(void) {
gnc_http * ret = g_new0(struct _gnc_http, 1);
ret->requests = NULL;
ret->callback_tag = 0;
ret->callback_enabled = FALSE;
return ret;
}
void
gnc_http_destroy(gnc_http * http) {
gnc_http_cancel_requests(http);
g_free(http);
}
void
gnc_http_cancel_requests(gnc_http * http) {
GList * current;
if(http->callback_enabled == TRUE) {
/* FIXME : should replace this with glib idle function -- bg */
gtk_timeout_remove(http->callback_tag);
http->callback_enabled = FALSE;
http->callback_tag = 0;
/* go through and destroy all the requests */
for(current = http->requests; current; current = current->next) {
if(current->data) {
struct request_info * r = current->data;
ghttp_request_destroy(r->request);
g_free(r->uri);
g_free(r);
current->data = NULL;
}
}
/* free the list backbone */
g_list_free(http->requests);
http->requests = NULL;
}
}
static gint
ghttp_check_callback(gpointer data) {
gnc_http * http = data;
GList * current;
ghttp_status status;
struct request_info * req;
/* walk the request list to deal with any complete requests */
for(current = http->requests; current; current = current->next) {
req = current->data;
status = ghttp_process(req->request);
switch(status) {
case ghttp_done:
if(req->callback) {
(req->callback)(req->uri, TRUE,
ghttp_get_body(req->request),
ghttp_get_body_len(req->request),
req->callback_data);
}
ghttp_request_destroy(req->request);
req->request = NULL;
current->data = NULL;
g_free(req);
break;
case ghttp_error:
if(req->callback) {
(req->callback)(req->uri, FALSE,
ghttp_get_error(req->request),
strlen(ghttp_get_error(req->request)),
req->callback_data);
}
ghttp_request_destroy(req->request);
req->request = NULL;
current->data = NULL;
g_free(req);
break;
case ghttp_not_done:
break;
}
}
/* walk the list again to remove dead requests */
current = http->requests;
while(current) {
if(current->data == NULL) {
http->requests = g_list_remove_link(http->requests, current);
current = http->requests;
}
else {
current = current->next;
}
}
/* if all requests are done, disable the timeout */
if(http->requests == NULL) {
http->callback_enabled = FALSE;
http->callback_tag = 0;
return FALSE;
}
else {
return TRUE;
}
}
#ifdef HAVE_OPENSSL
static int
gnc_http_certificate_check_cb(ghttp_request * req, X509 * cert,
void * user_data) {
PINFO("checking SSL certificate...");
X509_print_fp(stdout, cert);
PINFO(" ... done\n");
return TRUE;
}
#endif
void
gnc_http_start_request(gnc_http * http, const gchar * uri,
GncHTTPRequestCB cb, gpointer user_data) {
struct request_info * info = g_new0(struct request_info, 1);
info->request = ghttp_request_new();
info->uri = g_strdup (uri);
info->callback = cb;
info->callback_data = user_data;
#ifdef HAVE_OPENSSL
ghttp_enable_ssl(info->request);
ghttp_set_ssl_certificate_callback(info->request,
gnc_http_certificate_check_cb,
(void *)http);
#endif
ghttp_set_uri(info->request, (char *)uri);
ghttp_set_header(info->request, http_hdr_User_Agent,
"gnucash/1.5 (Financial Browser for Linux; http://gnucash.org)");
ghttp_set_sync(info->request, ghttp_async);
ghttp_set_type(info->request, ghttp_type_get);
ghttp_prepare(info->request);
ghttp_process(info->request);
http->requests = g_list_append(http->requests, info);
/* start the gtk timeout if not started */
/* FIXME : should replace this with glib idle function -- bg */
if(!http->callback_enabled) {
http->callback_tag =
gtk_timeout_add(100, ghttp_check_callback, (gpointer)http);
http->callback_enabled = TRUE;
}
}
void
gnc_http_start_post(gnc_http * http, const char * uri,
const char * content_type,
const char * data, int datalen,
GncHTTPRequestCB cb, gpointer user_data) {
struct request_info * info = g_new0(struct request_info, 1);
info->request = ghttp_request_new();
info->uri = g_strdup (uri);
info->callback = cb;
info->callback_data = user_data;
#ifdef HAVE_OPENSSL
ghttp_enable_ssl(info->request);
ghttp_set_ssl_certificate_callback(info->request,
gnc_http_certificate_check_cb,
(void *)http);
#endif
ghttp_set_uri(info->request, uri);
ghttp_set_header(info->request, http_hdr_User_Agent,
"gnucash/1.5 (Financial Browser for Linux; http://gnucash.org)");
ghttp_set_header(info->request, http_hdr_Content_Type, content_type);
ghttp_set_sync(info->request, ghttp_async);
ghttp_set_type(info->request, ghttp_type_post);
ghttp_set_body(info->request, data, datalen);
ghttp_prepare(info->request);
ghttp_process(info->request);
http->requests = g_list_append(http->requests, info);
/* start the gtk timeout if not started */
if(!http->callback_enabled) {
http->callback_tag =
gtk_timeout_add(100, ghttp_check_callback, (gpointer)http);
http->callback_enabled = TRUE;
}
}

43
src/gnome/gnc-http.h Normal file
View File

@@ -0,0 +1,43 @@
/********************************************************************
* gnc-http.h -- handle HTTP requests. thin wrapper on gnome-http. *
* Copyright (C) 2001 Bill Gribble <grib@billgribble.com> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
********************************************************************/
#ifndef __GNC_HTTP_H__
#define __GNC_HTTP_H__
#include <glib.h>
typedef struct _gnc_http gnc_http;
typedef void (* GncHTTPRequestCB)(const char * uri, int completed_ok,
const char * body, int body_len,
gpointer user_data);
gnc_http * gnc_http_new(void);
void gnc_http_destroy(gnc_http * html);
void gnc_http_start_request(gnc_http * http, const char * uri,
GncHTTPRequestCB cb, gpointer user_data);
void gnc_http_start_post(gnc_http * http, const char * uri,
const char * content_type,
const char * body, int body_len,
GncHTTPRequestCB cb, gpointer user_data);
void gnc_http_cancel_requests(gnc_http * http);
#endif

View File

@@ -25,11 +25,7 @@
#include "config.h"
#include <gnome.h>
#include <gtkhtml/gtkhtml.h>
#include <guile/gh.h>
#ifdef USE_GUPPI
#include <libguppitank/guppi-tank.h>
#endif
#include <popt.h>
#include <stdlib.h>
@@ -50,6 +46,13 @@
#include "gnc-component-manager.h"
#include "gnc-engine-util.h"
#include "gnc-splash.h"
#include "gnc-html-actions.h"
#ifdef USE_GUPPI
#include "gnc-html-guppi.h"
#endif
#ifdef USE_GPG
#include "gnc-gpg.h"
#endif
#include "gnc-ui.h"
#include "gnc.h"
#include "gnucash-color.h"
@@ -212,9 +215,15 @@ gnucash_ui_init(void)
gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
gtk_widget_set_default_visual (gdk_rgb_get_visual ());
/* load default HTML action handlers */
gnc_html_actions_init();
#ifdef USE_GUPPI
/* initialize guppi */
guppi_tank_init();
/* initialize guppi handling in gnc-html */
gnc_html_guppi_init();
#endif
#ifdef USE_GPG
/* initialize gpg handling in gnc-html */
gnc_gpg_init();
#endif
/* put up splash screen */

View File

@@ -655,9 +655,22 @@ gnc_help_window_new (void) {
void
gnc_help_window_destroy(gnc_help_window * help) {
if (!help) return;
gnc_unregister_gui_component_by_data (WINDOW_HELP_CM_CLASS, help);
gtk_signal_disconnect_by_func(GTK_OBJECT(help->toplevel),
GTK_SIGNAL_FUNC(gnc_help_window_destroy_cb),
(gpointer)help);
/* close the help index db */
if(help->index_db) {
help->index_db->close(help->index_db);
}
/* take care of the gnc-html object specially */
gtk_widget_ref(gnc_html_get_widget(help->html));
gnc_html_destroy(help->html);
gtk_widget_destroy(GTK_WIDGET(help->toplevel));
}

View File

@@ -118,6 +118,34 @@
#f
entities)))
;; I'm not entirely pleased about the way this works, but I can't
;; really see a way around it. It still works within the style
;; system, but it flattens out its children's lists prematurely. Has
;; to, to pass them as args to sprintf.
(define (gnc:html-markup/format format . entities)
(lambda (doc)
(apply
sprintf #f format
(map
(lambda (elt)
(let ((rendered-elt
(cond ((procedure? elt)
(elt doc))
((gnc:html-object? elt)
(gnc:html-object-render elt doc))
(#t
(gnc:html-document-render-data doc elt)))))
(cond
((string? rendered-elt)
rendered-elt)
((list? rendered-elt)
(apply string-append (gnc:report-tree-collapse rendered-elt)))
(#t
(simple-format "hold on there podner. form='~s'\n" rendered-elt)
""))))
entities))))
(define (gnc:html-markup-p . rest)
(apply gnc:html-markup "p" rest))
@@ -182,9 +210,10 @@
(gnc:html-document-push-style doc (gnc:html-text-style p))
(for-each-in-order
(lambda (elt)
(if (procedure? elt)
(push (elt doc))
(push (gnc:html-document-render-data doc elt))))
(cond ((procedure? elt)
(push (elt doc)))
(#t
(push (gnc:html-document-render-data doc elt)))))
(gnc:html-text-body p))
(gnc:html-document-pop-style doc)
(gnc:html-style-table-uncompile (gnc:html-text-style p))
@@ -195,10 +224,11 @@
(push (lambda (l) (set! retval (cons l retval)))))
(push (gnc:html-document-markup-start doc markup attrib))
(for-each-in-order
(lambda (elt)
(if (procedure? elt)
(push (elt doc))
(push (gnc:html-document-render-data doc elt))))
(lambda (elt)
(cond ((procedure? elt)
(push (elt doc)))
(#t
(push (gnc:html-document-render-data doc elt)))))
entities)
(if end-tag?
(push (gnc:html-document-markup-end doc markup)))

View File

@@ -357,16 +357,19 @@ new, totally cool report, consult the mailing list ")
(gnc:html-markup-b date-string2) ".")
(gnc:html-markup-p
(_ "The relative date option is ")
(gnc:html-markup-b rel-date-string) ".")
(gnc:html-markup/format
(_ "The relative date option is %a.")
(gnc:html-markup-b rel-date-string)))
(gnc:html-markup-p
(_ "The combination date option is ")
(gnc:html-markup-b combo-date-string) ".")
(gnc:html-markup/format
(_ "The combination date option is %a.")
(gnc:html-markup-b combo-date-string)))
(gnc:html-markup-p
(_ "The number option is ")
(gnc:html-markup-b (number->string num-val)) ".")
(gnc:html-markup/format
(_ "The number option is %a.")
(gnc:html-markup-b (number->string num-val))))
;; Here we print the value of the number option formatted as
;; currency. When printing currency values, you should use
@@ -375,10 +378,11 @@ new, totally cool report, consult the mailing list ")
;; appropriately in the current locale. Don't try to format
;; it yourself -- it will be wrong in other locales.
(gnc:html-markup-p
(_ "The number option formatted as currency is ")
(gnc:html-markup-b
(gnc:amount->string num-val (gnc:default-print-info #f))))))
(gnc:html-markup/format
(_ "The number option formatted as currency is %a.")
(gnc:html-markup-b
(gnc:amount->string num-val (gnc:default-print-info #f)))))))
;; you can add as many objects as you want. Here's another
;; one. We'll make a single-column table of the selected list
;; options just for grins.