33 #include <glib/gi18n.h> 34 #include <glib/gstdio.h> 35 #include <sys/types.h> 48 #include "gnc-html-history.h" 51 static QofLogModule log_module = GNC_MOD_HTML;
54 static GHashTable * gnc_html_type_to_proto_hash = NULL;
55 GHashTable * gnc_html_proto_to_type_hash = NULL;
58 GHashTable* gnc_html_object_handlers = NULL;
61 GHashTable* gnc_html_stream_handlers = NULL;
64 GHashTable* gnc_html_url_handlers = NULL;
67 extern GHashTable* gnc_html_object_handlers;
69 G_DEFINE_ABSTRACT_TYPE(GncHtml, gnc_html, GTK_TYPE_BIN)
71 static void gnc_html_dispose( GObject* obj );
72 static void gnc_html_finalize( GObject* obj );
77 #define GNC_HTML_GET_PRIVATE(o) (GNC_HTML(o)->priv) 79 #include "gnc-html-p.h" 82 gnc_html_class_init( GncHtmlClass* klass )
84 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
86 gobject_class->dispose = gnc_html_dispose;
87 gobject_class->finalize = gnc_html_finalize;
89 klass->show_url = NULL;
90 klass->show_data = NULL;
92 klass->copy_to_clipboard = NULL;
93 klass->export_to_file = NULL;
96 klass->parse_url = NULL;
97 klass->set_parent = NULL;
101 gnc_html_init( GncHtml*
self )
103 GncHtmlPrivate* priv;
104 priv =
self->priv = g_new0( GncHtmlPrivate, 1 );
106 priv->container = gtk_scrolled_window_new( NULL, NULL );
107 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(priv->container),
108 GTK_POLICY_AUTOMATIC,
109 GTK_POLICY_AUTOMATIC );
111 priv->request_info = g_hash_table_new( g_str_hash, g_str_equal );
112 priv->history = gnc_html_history_new();
116 gnc_html_dispose( GObject* obj )
118 GncHtml*
self = GNC_HTML(obj);
119 GncHtmlPrivate* priv = GNC_HTML_GET_PRIVATE(
self);
121 if ( priv->container != NULL )
123 gtk_widget_destroy( GTK_WIDGET(priv->container) );
124 g_object_unref( G_OBJECT(priv->container) );
125 priv->container = NULL;
127 if ( priv->request_info != NULL )
129 g_hash_table_destroy( priv->request_info );
130 priv->request_info = NULL;
132 if ( priv->history != NULL )
134 gnc_html_history_destroy( priv->history );
135 priv->history = NULL;
138 G_OBJECT_CLASS(gnc_html_parent_class)->dispose( obj );
142 gnc_html_finalize( GObject* obj )
144 GncHtml*
self = GNC_HTML(obj);
146 if ( self->priv != NULL )
148 g_free( self->priv );
152 G_OBJECT_CLASS(gnc_html_parent_class)->finalize( obj );
158 extract_machine_name(
const gchar* path )
160 gchar machine_rexp[] =
"^(//[^/]*)/*(.*)?$";
163 gchar* machine = NULL;
165 if ( path == NULL )
return NULL;
167 regcomp( &compiled_m, machine_rexp, REG_EXTENDED );
171 if ( !regexec( &compiled_m, path, 4, match, 0 ) )
174 if ( match[1].rm_so != -1 )
176 machine = g_strndup( path + match[1].rm_so, match[1].rm_eo - match[1].rm_so );
179 regfree(&compiled_m);
190 gnc_html_parse_url( GncHtml*
self,
const gchar* url,
191 gchar** url_location, gchar** url_label )
193 gchar uri_rexp[] =
"^(([^:][^:]+):)?([^#]+)?(#(.*))?$";
196 gchar* protocol = NULL;
199 gboolean found_protocol = FALSE;
200 gboolean found_path = FALSE;
201 gboolean found_label = FALSE;
203 GncHtmlPrivate* priv = GNC_HTML_GET_PRIVATE(
self);
205 g_return_val_if_fail(
self != NULL, NULL );
206 g_return_val_if_fail( GNC_IS_HTML(
self), NULL );
208 DEBUG(
"parsing %s, base_location %s",
209 url ? url :
"(null)",
210 self ? (priv->base_location ? priv->base_location
211 :
"(null base_location)")
214 regcomp( &compiled, uri_rexp, REG_EXTENDED );
216 if ( !regexec( &compiled, url, 6, match, 0 ) )
218 if ( match[2].rm_so != -1 )
220 protocol = g_new0( gchar, match[2].rm_eo - match[2].rm_so + 1 );
221 strncpy( protocol, url + match[2].rm_so, match[2].rm_eo - match[2].rm_so );
222 protocol[match[2].rm_eo - match[2].rm_so] = 0;
223 found_protocol = TRUE;
225 if ( match[3].rm_so != -1 )
227 path = g_new0( gchar, match[3].rm_eo - match[3].rm_so + 1 );
228 strncpy( path, url + match[3].rm_so, match[3].rm_eo - match[3].rm_so );
229 path[match[3].rm_eo - match[3].rm_so] = 0;
232 if ( match[5].rm_so != -1 )
234 label = g_new0( gchar, match[5].rm_eo - match[5].rm_so + 1 );
235 strncpy( label, url + match[5].rm_so, match[5].rm_eo - match[5].rm_so );
236 label[match[5].rm_eo - match[5].rm_so] = 0;
241 regfree( &compiled );
243 if ( found_protocol )
245 retval = g_hash_table_lookup( gnc_html_proto_to_type_hash, protocol );
246 if ( retval == NULL )
248 PWARN(
"unhandled URL type for '%s'", url ? url :
"(null)" );
249 retval = URL_TYPE_OTHER;
252 else if ( found_label && !found_path )
254 retval = URL_TYPE_JUMP;
260 retval = priv->base_type;
264 retval = URL_TYPE_FILE;
270 if ( !g_strcmp0( retval, URL_TYPE_FILE ) )
272 if ( !found_protocol && path &&
self && priv->base_location )
274 if ( g_path_is_absolute( path ) )
276 *url_location = g_strdup( path );
280 *url_location = g_build_filename( priv->base_location, path, (gchar*)NULL );
286 *url_location = g_strdup( path );
291 else if ( !g_strcmp0( retval, URL_TYPE_JUMP ) )
293 *url_location = NULL;
301 if ( !found_protocol && path &&
self && priv->base_location )
303 if ( g_path_is_absolute( path ) )
305 *url_location = g_build_filename( extract_machine_name( priv->base_location ),
306 path, (gchar*)NULL );
310 *url_location = g_build_filename( priv->base_location, path, (gchar*)NULL );
316 *url_location = g_strdup( path );
332 gnc_html_show_data( GncHtml*
self,
const gchar* data,
int datalen )
334 g_return_if_fail(
self != NULL );
335 g_return_if_fail( GNC_IS_HTML(
self) );
337 if ( GNC_HTML_GET_CLASS(
self)->show_data != NULL )
339 GNC_HTML_GET_CLASS(
self)->show_data(
self, data, datalen );
343 DEBUG(
"'show_data' not implemented" );
357 gnc_html_show_url( GncHtml*
self, URLType type,
358 const gchar* location,
const gchar* label,
359 gboolean new_window_hint )
361 char* lc_type = NULL;
363 g_return_if_fail(
self != NULL );
364 g_return_if_fail( GNC_IS_HTML(
self) );
366 lc_type = g_ascii_strdown (type, -1);
367 if ( GNC_HTML_GET_CLASS(
self)->show_url != NULL )
369 GNC_HTML_GET_CLASS(
self)->show_url(
self, lc_type, location, label, new_window_hint );
373 DEBUG(
"'show_url' not implemented" );
388 gnc_html_reload( GncHtml*
self, gboolean force_rebuild )
390 g_return_if_fail(
self != NULL );
391 g_return_if_fail( GNC_IS_HTML(
self) );
393 if ( GNC_HTML_GET_CLASS(
self)->reload != NULL )
395 GNC_HTML_GET_CLASS(
self)->reload(
self, force_rebuild );
399 DEBUG(
"'reload' not implemented" );
409 gnc_html_cancel( GncHtml*
self )
411 g_return_if_fail(
self != NULL );
412 g_return_if_fail( GNC_IS_HTML(
self) );
414 if ( GNC_HTML_GET_CLASS(
self)->cancel != NULL )
416 GNC_HTML_GET_CLASS(
self)->cancel(
self );
420 DEBUG(
"'cancel' not implemented" );
431 gnc_html_destroy( GncHtml*
self )
433 g_return_if_fail(
self != NULL );
434 g_return_if_fail( GNC_IS_HTML(
self) );
436 if ( g_object_is_floating( G_OBJECT(
self) ) )
438 (void)g_object_ref_sink( G_OBJECT(
self) );
441 g_object_unref( G_OBJECT(
self) );
445 gnc_html_set_urltype_cb( GncHtml*
self, GncHTMLUrltypeCB urltype_cb )
447 GncHtmlPrivate* priv;
449 g_return_if_fail(
self != NULL );
450 g_return_if_fail( GNC_IS_HTML(
self) );
452 priv = GNC_HTML_GET_PRIVATE(
self);
453 priv->urltype_cb = urltype_cb;
457 gnc_html_set_load_cb( GncHtml*
self, GncHTMLLoadCB load_cb, gpointer data )
459 GncHtmlPrivate* priv;
461 g_return_if_fail(
self != NULL );
462 g_return_if_fail( GNC_IS_HTML(
self) );
464 priv = GNC_HTML_GET_PRIVATE(
self);
465 priv->load_cb = load_cb;
466 priv->load_cb_data = data;
470 gnc_html_set_flyover_cb( GncHtml*
self, GncHTMLFlyoverCB flyover_cb, gpointer data )
472 GncHtmlPrivate* priv;
474 g_return_if_fail(
self != NULL );
475 g_return_if_fail( GNC_IS_HTML(
self) );
477 priv = GNC_HTML_GET_PRIVATE(
self);
478 priv->flyover_cb = flyover_cb;
479 priv->flyover_cb_data = data;
483 gnc_html_set_button_cb( GncHtml*
self, GncHTMLButtonCB button_cb, gpointer data )
485 GncHtmlPrivate* priv;
487 g_return_if_fail(
self != NULL );
488 g_return_if_fail( GNC_IS_HTML(
self) );
490 priv = GNC_HTML_GET_PRIVATE(
self);
491 priv->button_cb = button_cb;
492 priv->button_cb_data = data;
496 gnc_html_copy_to_clipboard( GncHtml*
self )
498 g_return_if_fail(
self != NULL );
499 g_return_if_fail( GNC_IS_HTML(
self) );
501 if ( GNC_HTML_GET_CLASS(
self)->copy_to_clipboard != NULL )
503 GNC_HTML_GET_CLASS(
self)->copy_to_clipboard(
self );
507 DEBUG(
"'copy_to_clipboard' not implemented" );
516 gnc_html_export_to_file( GncHtml*
self,
const gchar* filepath )
518 g_return_val_if_fail(
self != NULL, FALSE );
519 g_return_val_if_fail( GNC_IS_HTML(
self), FALSE );
521 if ( GNC_HTML_GET_CLASS(
self)->export_to_file != NULL )
523 return GNC_HTML_GET_CLASS(
self)->export_to_file(
self, filepath );
527 DEBUG(
"'export_to_file' not implemented" );
533 gnc_html_print (GncHtml*
self,
const char *jobname, gboolean export_pdf)
536 gnc_html_print (GncHtml*
self,
const char *jobname)
539 g_return_if_fail(
self != NULL );
540 g_return_if_fail( jobname != NULL );
541 g_return_if_fail( GNC_IS_HTML(
self) );
543 if ( GNC_HTML_GET_CLASS(
self)->print != NULL )
546 GNC_HTML_GET_CLASS(
self)->print (
self, jobname, export_pdf);
548 GNC_HTML_GET_CLASS(
self)->print (
self, jobname);
553 DEBUG(
"'print' not implemented" );
558 gnc_html_get_history( GncHtml*
self )
560 g_return_val_if_fail(
self != NULL, NULL );
561 g_return_val_if_fail( GNC_IS_HTML(
self), NULL );
563 return GNC_HTML_GET_PRIVATE(
self)->history;
568 gnc_html_get_widget( GncHtml*
self )
570 g_return_val_if_fail(
self != NULL, NULL );
571 g_return_val_if_fail( GNC_IS_HTML(
self), NULL );
573 return GNC_HTML_GET_PRIVATE(
self)->container;
578 gnc_html_get_webview( GncHtml*
self )
580 GncHtmlPrivate* priv;
581 GList *sw_list = NULL;
582 GtkWidget *webview = NULL;
584 g_return_val_if_fail (
self != NULL, NULL);
585 g_return_val_if_fail (GNC_IS_HTML(
self), NULL);
587 priv = GNC_HTML_GET_PRIVATE(
self);
588 sw_list = gtk_container_get_children (GTK_CONTAINER(priv->container));
593 webview = sw_list->data;
595 GList *vp_list = gtk_container_get_children (GTK_CONTAINER(sw_list->data));
599 webview = vp_list->data;
600 g_list_free (vp_list);
604 g_list_free (sw_list);
610 gnc_html_set_parent( GncHtml*
self, GtkWindow* parent )
612 g_return_if_fail(
self != NULL );
613 g_return_if_fail( GNC_IS_HTML(
self) );
615 if ( GNC_HTML_GET_CLASS(
self)->set_parent != NULL )
617 GNC_HTML_GET_CLASS(
self)->set_parent(
self, parent );
621 DEBUG(
"'set_parent' not implemented" );
629 gnc_html_register_urltype( URLType type,
const char *protocol )
631 char* lc_type = NULL;
632 char *lc_proto = NULL;
634 if (!gnc_html_type_to_proto_hash)
636 gnc_html_type_to_proto_hash = g_hash_table_new (g_str_hash, g_str_equal);
637 gnc_html_proto_to_type_hash = g_hash_table_new (g_str_hash, g_str_equal);
639 if (!protocol)
return FALSE;
641 lc_type = g_ascii_strdown (type, -1);
642 if (g_hash_table_lookup (gnc_html_type_to_proto_hash, lc_type))
648 lc_proto = g_ascii_strdown (protocol, -1);
649 g_hash_table_insert (gnc_html_type_to_proto_hash, lc_type, (gpointer)lc_proto);
651 g_hash_table_insert (gnc_html_proto_to_type_hash, (gpointer)lc_proto, lc_type);
657 gnc_html_initialize(
void )
666 { URL_TYPE_FILE,
"file" },
667 { URL_TYPE_JUMP,
"" },
668 { URL_TYPE_HTTP,
"http" },
669 { URL_TYPE_FTP,
"ftp" },
670 { URL_TYPE_SECURE,
"https" },
671 { URL_TYPE_REGISTER,
"gnc-register" },
672 { URL_TYPE_ACCTTREE,
"gnc-acct-tree" },
673 { URL_TYPE_REPORT,
"gnc-report" },
674 { URL_TYPE_OPTIONS,
"gnc-options" },
675 { URL_TYPE_SCHEME,
"gnc-scm" },
676 { URL_TYPE_HELP,
"gnc-help" },
677 { URL_TYPE_XMLDATA,
"gnc-xml" },
678 { URL_TYPE_PRICE,
"gnc-price" },
679 { URL_TYPE_BUDGET,
"gnc-budget" },
680 { URL_TYPE_OTHER,
"" },
684 for (i = 0; types[i].type; i++)
685 gnc_html_register_urltype (types[i].type, types[i].protocol);
697 gnc_build_url( URLType type,
const gchar* location,
const gchar* label )
699 char* lc_type = NULL;
703 lc_type = g_ascii_strdown (type, -1);
704 type_name = g_hash_table_lookup (gnc_html_type_to_proto_hash, lc_type);
711 return g_strdup_printf(
"%s%s%s#%s", type_name, (*type_name ?
":" :
""),
712 (location ? location :
""),
717 return g_strdup_printf(
"%s%s%s", type_name, (*type_name ?
":" :
""),
718 (location ? location :
""));
733 gnc_html_encode_string(
const char * str)
735 static gchar *safe =
"$-._!*(),";
737 GString *encoded = g_string_new (
"");
738 static const size_t buf_size = 5;
739 gchar buffer[buf_size], *ptr;
742 if (!str)
return NULL;
744 while (pos < strlen(str))
746 c = (
unsigned char) str[pos];
748 if ((( c >=
'A') && ( c <=
'Z')) ||
749 (( c >=
'a') && ( c <=
'z')) ||
750 (( c >=
'0') && ( c <=
'9')) ||
753 encoded = g_string_append_c (encoded, c);
757 encoded = g_string_append_c (encoded,
'+');
759 else if ( c ==
'\n' )
761 encoded = g_string_append (encoded,
"%0D%0A");
763 else if ( c !=
'\r' )
765 snprintf( buffer, buf_size,
"%%%02X", (
int)c );
766 encoded = g_string_append (encoded, buffer);
771 ptr = g_string_free (encoded, FALSE);
778 gnc_html_decode_string(
const char * str)
780 static gchar * safe =
"$-._!*(),";
781 GString * decoded = g_string_new (
"");
787 if (!str)
return NULL;
791 c = (
unsigned char) * ptr;
792 if ((( c >=
'A') && ( c <=
'Z')) ||
793 (( c >=
'a') && ( c <=
'z')) ||
794 (( c >=
'0') && ( c <=
'9')) ||
797 decoded = g_string_append_c (decoded, c);
801 decoded = g_string_append_c (decoded,
' ');
803 else if (!strncmp(ptr,
"%0D0A", 5))
805 decoded = g_string_append (decoded,
"\n");
811 if (1 == sscanf(ptr,
"%02X", &hexval))
812 decoded = g_string_append_c(decoded, (
char)hexval);
814 decoded = g_string_append_c(decoded,
' ');
819 ptr = g_string_free (decoded, FALSE);
830 gnc_html_unescape_newlines(
const gchar * in)
832 const char * ip = in;
834 GString * rv = g_string_new(
"");
836 for (ip = in; *ip; ip++)
838 if ((*ip ==
'\\') && (*(ip + 1) ==
'n'))
840 g_string_append(rv,
"\n");
845 g_string_append_c(rv, *ip);
849 g_string_append_c(rv, 0);
850 cstr = g_string_free (rv, FALSE);
855 gnc_html_escape_newlines(
const gchar * in)
858 const char * ip = in;
859 GString * escaped = g_string_new(
"");
861 for (ip = in; *ip; ip++)
865 g_string_append(escaped,
"\\n");
869 g_string_append_c(escaped, *ip);
872 g_string_append_c(escaped, 0);
873 out = g_string_free (escaped, FALSE);
878 gnc_html_register_object_handler(
const char * classid,
879 GncHTMLObjectCB hand )
881 g_return_if_fail( classid != NULL );
883 if ( gnc_html_object_handlers == NULL )
885 gnc_html_object_handlers = g_hash_table_new( g_str_hash, g_str_equal );
888 gnc_html_unregister_object_handler( classid );
891 gchar *lc_id = g_ascii_strdown (classid, -1);
892 g_hash_table_insert( gnc_html_object_handlers, lc_id, hand );
897 gnc_html_unregister_object_handler(
const gchar* classid )
899 gchar* keyptr = NULL;
900 gchar* valptr = NULL;
901 gchar** p_keyptr = &keyptr;
902 gchar** p_valptr = &valptr;
903 gchar* lc_id = g_ascii_strdown (classid, -1);
905 if ( g_hash_table_lookup_extended( gnc_html_object_handlers,
907 (gpointer *)p_keyptr,
908 (gpointer *)p_valptr) )
910 g_hash_table_remove( gnc_html_object_handlers, lc_id );
917 gnc_html_register_stream_handler( URLType url_type, GncHTMLStreamCB hand )
919 g_return_if_fail( url_type != NULL && *url_type !=
'\0' );
921 if ( gnc_html_stream_handlers == NULL )
923 gnc_html_stream_handlers = g_hash_table_new( g_str_hash, g_str_equal );
926 gnc_html_unregister_stream_handler( url_type );
929 char* lc_type = g_ascii_strdown (url_type, -1);
930 g_hash_table_insert( gnc_html_stream_handlers, lc_type, hand );
935 gnc_html_unregister_stream_handler( URLType url_type )
937 char* lc_type = g_ascii_strdown (url_type, -1);
938 g_hash_table_remove( gnc_html_stream_handlers, lc_type );
943 gnc_html_register_url_handler( URLType url_type, GncHTMLUrlCB hand )
945 g_return_if_fail( url_type != NULL && *url_type !=
'\0' );
947 if ( gnc_html_url_handlers == NULL )
949 gnc_html_url_handlers = g_hash_table_new( g_str_hash, g_str_equal );
952 gnc_html_unregister_url_handler( url_type );
955 char* lc_type = g_ascii_strdown (url_type, -1);
956 g_hash_table_insert( gnc_html_url_handlers, lc_type, hand );
961 gnc_html_unregister_url_handler( URLType url_type )
963 char* lc_type = g_ascii_strdown (url_type, -1);
964 g_hash_table_remove( gnc_html_url_handlers, lc_type );
#define DEBUG(format, args...)
Print a debugging message.
#define PWARN(format, args...)
Log a warning.
Account handling public routines.
All type declarations for the whole Gnucash engine.