diff options
Diffstat (limited to 'e-util')
-rw-r--r-- | e-util/Makefile.am | 24 | ||||
-rw-r--r-- | e-util/e-account-utils.c | 96 | ||||
-rw-r--r-- | e-util/e-account-utils.h (renamed from e-util/e-corba-utils.c) | 36 | ||||
-rw-r--r-- | e-util/e-dialog-utils.c | 26 | ||||
-rw-r--r-- | e-util/e-dialog-utils.h | 2 | ||||
-rw-r--r-- | e-util/e-logger.c | 76 | ||||
-rw-r--r-- | e-util/e-logger.h | 26 | ||||
-rw-r--r-- | e-util/e-marshal.list | 1 | ||||
-rw-r--r-- | e-util/e-module.c | 318 | ||||
-rw-r--r-- | e-util/e-module.h | 81 | ||||
-rw-r--r-- | e-util/e-non-intrusive-error-dialog.c | 1 | ||||
-rw-r--r-- | e-util/e-non-intrusive-error-dialog.h | 2 | ||||
-rw-r--r-- | e-util/e-plugin-ui.c | 438 | ||||
-rw-r--r-- | e-util/e-plugin-ui.h | 9 | ||||
-rw-r--r-- | e-util/e-signature-utils.c | 347 | ||||
-rw-r--r-- | e-util/e-signature-utils.h (renamed from e-util/e-corba-utils.h) | 31 | ||||
-rw-r--r-- | e-util/e-unicode.c | 2052 | ||||
-rw-r--r-- | e-util/e-unicode.h | 113 | ||||
-rw-r--r-- | e-util/e-util-labels.c | 586 | ||||
-rw-r--r-- | e-util/e-util-labels.h | 57 | ||||
-rw-r--r-- | e-util/e-util.c | 45 | ||||
-rw-r--r-- | e-util/e-util.h | 14 | ||||
-rw-r--r-- | e-util/gconf-bridge.c | 6 |
23 files changed, 3463 insertions, 924 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 367a9c79d7..934c20b593 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -4,7 +4,6 @@ ecpsdir = $(privdatadir)/ecps ruledir = $(privdatadir) if OS_WIN32 -WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libemiscwidgets.la PLATFORM_SOURCES = e-win32-reloc.c endif @@ -34,18 +33,18 @@ INCLUDES = \ -DSEARCH_RULE_DIR=\"$(ruledir)\" \ -DG_LOG_DOMAIN=\"e-utils\" \ $(GNOME_PILOT_CFLAGS) \ - $(ICONV_CFLAGS) \ + $(ICONV_CFLAGS) \ $(E_UTIL_CFLAGS) privsolib_LTLIBRARIES = libeutil.la libeconduit.la eutilinclude_HEADERS = \ + e-account-utils.h \ e-bconf-map.h \ e-binding.h \ e-categories-config.h \ e-config.h \ e-config-listener.h \ - e-corba-utils.h \ e-cursor.h \ e-dialog-utils.h \ e-dialog-widgets.h \ @@ -57,10 +56,11 @@ eutilinclude_HEADERS = \ e-icon-factory.h \ e-import.h \ e-logger.h \ - e-non-intrusive-error-dialog.h \ e-marshal.h \ e-menu.h \ e-mktemp.h \ + e-module.h \ + e-non-intrusive-error-dialog.h \ e-print.h \ e-plugin.h \ e-plugin-ui.h \ @@ -69,6 +69,7 @@ eutilinclude_HEADERS = \ e-request.h \ e-signature.h \ e-signature-list.h \ + e-signature-utils.h \ e-bit-array.h \ e-sorter.h \ e-sorter-array.h \ @@ -76,17 +77,17 @@ eutilinclude_HEADERS = \ e-text-event-processor-types.h \ e-text-event-processor.h \ e-util.h \ - e-util-labels.h \ + e-unicode.h \ e-xml-utils.h libeutil_la_SOURCES = \ $(eutilinclude_HEADERS) \ + e-account-utils.c \ e-bconf-map.c \ e-binding.c \ e-categories-config.c \ - e-config.c \ e-config-listener.c \ - e-corba-utils.c \ + e-config.c \ e-cursor.c \ e-dialog-utils.c \ e-dialog-widgets.c \ @@ -98,25 +99,27 @@ libeutil_la_SOURCES = \ e-icon-factory.c \ e-import.c \ e-logger.c \ - e-non-intrusive-error-dialog.c \ e-marshal.c \ e-menu.c \ e-mktemp.c \ - e-plugin.c \ + e-module.c \ + e-non-intrusive-error-dialog.c \ e-plugin-ui.c \ + e-plugin.c \ e-popup.c \ e-print.c \ e-profile-event.c \ e-request.c \ e-signature.c \ e-signature-list.c \ + e-signature-utils.c \ e-bit-array.c \ e-sorter.c \ e-sorter-array.c \ e-text-event-processor-emacs-like.c \ e-text-event-processor.c \ e-util.c \ - e-util-labels.c \ + e-unicode.c \ e-util-private.h \ e-xml-utils.c \ gconf-bridge.c \ @@ -129,7 +132,6 @@ MARSHAL_GENERATED = e-marshal.c e-marshal.h libeutil_la_LDFLAGS = $(NO_UNDEFINED) libeutil_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ $(ICONV_LIBS) \ $(E_UTIL_LIBS) \ $(GNOME_PILOT_LIBS) \ diff --git a/e-util/e-account-utils.c b/e-util/e-account-utils.c new file mode 100644 index 0000000000..d98a378b48 --- /dev/null +++ b/e-util/e-account-utils.c @@ -0,0 +1,96 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#include "e-account-utils.h" + +#include <gconf/gconf-client.h> + +static EAccountList *global_account_list; + +EAccountList * +e_get_account_list (void) +{ + if (G_UNLIKELY (global_account_list == NULL)) { + GConfClient *client; + + client = gconf_client_get_default (); + global_account_list = e_account_list_new (client); + g_object_unref (client); + } + + g_return_val_if_fail (global_account_list != NULL, NULL); + + return global_account_list; +} + +EAccount * +e_get_default_account (void) +{ + EAccountList *account_list; + const EAccount *account; + + account_list = e_get_account_list (); + account = e_account_list_get_default (account_list); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +void +e_set_default_account (EAccount *account) +{ + EAccountList *account_list; + + g_return_if_fail (E_IS_ACCOUNT (account)); + + account_list = e_get_account_list (); + e_account_list_set_default (account_list, account); +} + +EAccount * +e_get_account_by_name (const gchar *name) +{ + EAccountList *account_list; + const EAccount *account; + e_account_find_t find; + + g_return_val_if_fail (name != NULL, NULL); + + find = E_ACCOUNT_FIND_NAME; + account_list = e_get_account_list (); + account = e_account_list_find (account_list, find, name); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +EAccount * +e_get_account_by_uid (const gchar *uid) +{ + EAccountList *account_list; + const EAccount *account; + e_account_find_t find; + + g_return_val_if_fail (uid != NULL, NULL); + + find = E_ACCOUNT_FIND_UID; + account_list = e_get_account_list (); + account = e_account_list_find (account_list, find, uid); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} diff --git a/e-util/e-corba-utils.c b/e-util/e-account-utils.h index 0288602a7e..24262349d2 100644 --- a/e-util/e-corba-utils.c +++ b/e-util/e-account-utils.h @@ -12,32 +12,24 @@ * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see <http://www.gnu.org/licenses/> * - * - * Authors: - * Ettore Perazzoli <ettore@ximian.com> - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif +#ifndef E_ACCOUNT_UTILS_H +#define E_ACCOUNT_UTILS_H + +#include <glib.h> +#include <libedataserver/e-account.h> +#include <libedataserver/e-account-list.h> -#include "e-corba-utils.h" +G_BEGIN_DECLS - -const CORBA_char * -e_safe_corba_string (const char *s) -{ - if (s == NULL) - return (CORBA_char *) ""; +EAccountList * e_get_account_list (void); +EAccount * e_get_default_account (void); +void e_set_default_account (EAccount *account); +EAccount * e_get_account_by_name (const gchar *name); +EAccount * e_get_account_by_uid (const gchar *uid); - return s; -} +G_END_DECLS -CORBA_char * -e_safe_corba_string_dup (const char *s) -{ - return CORBA_string_dup (e_safe_corba_string (s)); -} +#endif /* E_ACCOUNT_UTILS_H */ diff --git a/e-util/e-dialog-utils.c b/e-util/e-dialog-utils.c index 0546430512..7d1d4836b6 100644 --- a/e-util/e-dialog-utils.c +++ b/e-util/e-dialog-utils.c @@ -344,29 +344,29 @@ e_file_dialog_save_folder (const char *title) * no signals connected and is not shown. **/ GtkWidget * -e_file_get_save_filesel (GtkWidget *parent, const char *title, const char *name, GtkFileChooserAction action) +e_file_get_save_filesel (GtkWindow *parent, const char *title, const char *name, GtkFileChooserAction action) { GtkWidget *filesel; char *uri; - filesel = gtk_file_chooser_dialog_new (title, - NULL, - action, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - (action == GTK_FILE_CHOOSER_ACTION_OPEN) ? GTK_STOCK_OPEN:GTK_STOCK_SAVE, GTK_RESPONSE_OK, - NULL); + g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); + + filesel = gtk_file_chooser_dialog_new ( + title, parent, action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + (action == GTK_FILE_CHOOSER_ACTION_OPEN) ? + GTK_STOCK_OPEN : GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filesel), FALSE); - if (parent) - e_dialog_set_transient_for((GtkWindow *)filesel, parent); - - uri = e_file_get_save_path(); + uri = e_file_get_save_path (); - gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (filesel), uri); + gtk_file_chooser_set_current_folder_uri ( + GTK_FILE_CHOOSER (filesel), uri); if (name && name[0]) - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filesel), name); + gtk_file_chooser_set_current_name ( + GTK_FILE_CHOOSER (filesel), name); g_free (uri); diff --git a/e-util/e-dialog-utils.h b/e-util/e-dialog-utils.h index 9d594122e2..9e6e7992c1 100644 --- a/e-util/e-dialog-utils.h +++ b/e-util/e-dialog-utils.h @@ -43,7 +43,7 @@ char *e_file_dialog_save (const char *title, const char *fname) char *e_file_dialog_save_folder (const char *title); -GtkWidget * e_file_get_save_filesel (GtkWidget *parent, const char *title, const char *name, GtkFileChooserAction action); +GtkWidget * e_file_get_save_filesel (GtkWindow *parent, const char *title, const char *name, GtkFileChooserAction action); gboolean e_file_can_save(GtkWindow *parent, const char *uri); gboolean e_file_check_local(const char *name); diff --git a/e-util/e-logger.c b/e-util/e-logger.c index 0a458b7444..97d27d03cf 100644 --- a/e-util/e-logger.c +++ b/e-util/e-logger.c @@ -43,7 +43,7 @@ ((obj), E_TYPE_LOGGER, ELoggerPrivate)) struct _ELoggerPrivate { - gchar *component; + gchar *name; gchar *logfile; FILE *fp; @@ -52,13 +52,13 @@ struct _ELoggerPrivate { enum { PROP_0, - PROP_COMPONENT + PROP_NAME }; static gpointer parent_class; static gboolean -flush_logfile (ELogger *logger) +logger_flush (ELogger *logger) { if (logger->priv->fp) fflush (logger->priv->fp); @@ -68,16 +68,26 @@ flush_logfile (ELogger *logger) } static void -logger_set_component (ELogger *logger, - const gchar *component) +logger_set_dirty (ELogger *logger) +{ + if (logger->priv->timer) + return; + + logger->priv->timer = g_timeout_add ( + TIMEOUT_INTERVAL, (GSourceFunc) logger_flush, logger); +} + +static void +logger_set_name (ELogger *logger, + const gchar *name) { gchar *temp; - g_return_if_fail (logger->priv->component == NULL); + g_return_if_fail (logger->priv->name == NULL); - temp = g_strdup_printf ("%s.log.XXXXXX", component); + temp = g_strdup_printf ("%s.log.XXXXXX", name); - logger->priv->component = g_strdup (component); + logger->priv->name = g_strdup (name); logger->priv->logfile = e_mktemp (temp); logger->priv->fp = g_fopen (logger->priv->logfile, "w"); logger->priv->timer = 0; @@ -95,8 +105,8 @@ logger_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_COMPONENT: - logger_set_component ( + case PROP_NAME: + logger_set_name ( E_LOGGER (object), g_value_get_string (value)); return; @@ -112,9 +122,9 @@ logger_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_COMPONENT: + case PROP_NAME: g_value_set_string ( - value, e_logger_get_component ( + value, e_logger_get_name ( E_LOGGER (object))); return; } @@ -129,11 +139,11 @@ logger_finalize (GObject *object) if (logger->priv->timer) g_source_remove (logger->priv->timer); - flush_logfile (logger); + logger_flush (logger); if (logger->priv->fp) fclose (logger->priv->fp); - g_free (logger->priv->component); + g_free (logger->priv->name); g_free (logger->priv->logfile); /* Chain up to parent's finalize() method. */ @@ -155,11 +165,11 @@ logger_class_init (ELoggerClass *class) g_object_class_install_property ( object_class, - PROP_COMPONENT, + PROP_NAME, g_param_spec_string ( - "component", - _("Component"), - _("Name of the component being logged"), + "name", + _("Name"), + _("Name of the logger"), "anonymous", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); @@ -198,34 +208,24 @@ e_logger_get_type (void) } ELogger * -e_logger_create (gchar *component) +e_logger_new (const gchar *name) { - g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); - return g_object_new (E_TYPE_LOGGER, "component", component, NULL); + return g_object_new (E_TYPE_LOGGER, "name", name, NULL); } const gchar * -e_logger_get_component (ELogger *logger) +e_logger_get_name (ELogger *logger) { g_return_val_if_fail (E_IS_LOGGER (logger), NULL); - return logger->priv->component; -} - -static void -set_dirty (ELogger *logger) -{ - if (logger->priv->timer) - return; - - logger->priv->timer = g_timeout_add_seconds ( - TIMEOUT_INTERVAL, (GSourceFunc) flush_logfile, logger); + return logger->priv->name; } void e_logger_log (ELogger *logger, - gint level, + ELogLevel level, gchar *primary, gchar *secondary) { @@ -240,13 +240,13 @@ e_logger_log (ELogger *logger, fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, primary); fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, secondary); - set_dirty (logger); + logger_set_dirty (logger); } void e_logger_get_logs (ELogger *logger, ELogFunction func, - gpointer data) + gpointer user_data) { FILE *fp; gchar buf[250]; @@ -288,11 +288,11 @@ e_logger_get_logs (ELogger *logger, g_string_append (str, tmp); } - func (str->str, data); + func (str->str, user_data); g_string_free (str, TRUE); } else - func (tmp, data); + func (tmp, user_data); } fclose (fp); diff --git a/e-util/e-logger.h b/e-util/e-logger.h index f7dfd8017e..ce595d691c 100644 --- a/e-util/e-logger.h +++ b/e-util/e-logger.h @@ -20,8 +20,8 @@ * */ -#ifndef __E_LOGGER_H__ -#define __E_LOGGER_H__ +#ifndef E_LOGGER_H +#define E_LOGGER_H #include <glib-object.h> @@ -52,34 +52,32 @@ typedef struct _ELoggerPrivate ELoggerPrivate; typedef void (*ELogFunction) (gchar *line, gpointer data); -enum e_log_level_t { +typedef enum { E_LOG_ERROR, - E_LOG_WARNINGS, + E_LOG_WARNING, E_LOG_DEBUG -}; +} ELogLevel; -/* The object */ struct _ELogger { GObject parent; - - struct _ELoggerPrivate *priv; + ELoggerPrivate *priv; }; struct _ELoggerClass { - GObjectClass popup_class; + GObjectClass parent_class; }; GType e_logger_get_type (void); -ELogger * e_logger_create (gchar *component); -const gchar * e_logger_get_component (ELogger *logger); +ELogger * e_logger_new (const gchar *name); +const gchar * e_logger_get_name (ELogger *logger); void e_logger_log (ELogger *logger, - gint level, + ELogLevel level, gchar *primary, gchar *secondary); void e_logger_get_logs (ELogger *logger, ELogFunction func, - gpointer data); + gpointer user_data); G_END_DECLS -#endif /* __E_LOGGER_H__ */ +#endif /* E_LOGGER_H */ diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list index 366602491b..b667ca4a84 100644 --- a/e-util/e-marshal.list +++ b/e-util/e-marshal.list @@ -66,3 +66,4 @@ NONE:STRING,STRING,STRING NONE:STRING,STRING,UINT OBJECT:OBJECT,DOUBLE,DOUBLE,BOOLEAN POINTER:NONE +STRING:NONE diff --git a/e-util/e-module.c b/e-util/e-module.c new file mode 100644 index 0000000000..51e1e18bd6 --- /dev/null +++ b/e-util/e-module.c @@ -0,0 +1,318 @@ +/* + * e-module.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-module.h" + +#include <glib/gi18n.h> + +/* This is the symbol we call when loading a module. */ +#define LOAD_SYMBOL "e_module_load" + +/* This is the symbol we call when unloading a module. */ +#define UNLOAD_SYMBOL "e_module_unload" + +#define E_MODULE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MODULE, EModulePrivate)) + +struct _EModulePrivate { + GModule *module; + gchar *filename; + + void (*load) (GTypeModule *type_module); + void (*unload) (GTypeModule *type_module); +}; + +enum { + PROP_0, + PROP_FILENAME +}; + +static gpointer parent_class; + +static void +module_set_filename (EModule *module, + const gchar *filename) +{ + g_return_if_fail (module->priv->filename == NULL); + + module->priv->filename = g_strdup (filename); +} + +static void +module_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILENAME: + module_set_filename ( + E_MODULE (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +module_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILENAME: + g_value_set_string ( + value, e_module_get_filename ( + E_MODULE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +module_finalize (GObject *object) +{ + EModulePrivate *priv; + + priv = E_MODULE_GET_PRIVATE (object); + + g_free (priv->filename); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +module_load (GTypeModule *type_module) +{ + EModulePrivate *priv; + gpointer symbol; + + priv = E_MODULE_GET_PRIVATE (type_module); + + g_return_val_if_fail (priv->filename != NULL, FALSE); + priv->module = g_module_open (priv->filename, 0); + + if (priv->module == NULL) + goto fail; + + if (!g_module_symbol (priv->module, LOAD_SYMBOL, &symbol)) + goto fail; + + priv->load = symbol; + + if (!g_module_symbol (priv->module, UNLOAD_SYMBOL, &symbol)) + goto fail; + + priv->unload = symbol; + + priv->load (type_module); + + return TRUE; + +fail: + g_warning ("%s", g_module_error ()); + + if (priv->module != NULL) + g_module_close (priv->module); + + return FALSE; +} + +static void +module_unload (GTypeModule *type_module) +{ + EModulePrivate *priv; + + priv = E_MODULE_GET_PRIVATE (type_module); + + priv->unload (type_module); + + g_module_close (priv->module); + priv->module = NULL; + + priv->load = NULL; + priv->unload = NULL; +} + +static void +module_class_init (EModuleClass *class) +{ + GObjectClass *object_class; + GTypeModuleClass *type_module_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EModulePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = module_set_property; + object_class->get_property = module_get_property; + object_class->finalize = module_finalize; + + type_module_class = G_TYPE_MODULE_CLASS (class); + type_module_class->load = module_load; + type_module_class->unload = module_unload; + + /** + * EModule:filename + * + * The filename of the module. + **/ + g_object_class_install_property ( + object_class, + PROP_FILENAME, + g_param_spec_string ( + "filename", + _("Filename"), + _("The filename of the module"), + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +module_init (EModule *module) +{ + module->priv = E_MODULE_GET_PRIVATE (module); +} + +GType +e_module_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EModuleClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) module_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EModule), + 0, /* n_preallocs */ + (GInstanceInitFunc) module_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_TYPE_MODULE, "EModule", &type_info, 0); + } + + return type; +} + +/** + * e_module_new: + * @filename: filename of the shared library module + * + * Creates a new #EModule that will load the specific shared library + * when in use. + * + * Returns: a new #EModule for @filename + **/ +EModule * +e_module_new (const gchar *filename) +{ + g_return_val_if_fail (filename != NULL, NULL); + + return g_object_new (E_TYPE_MODULE, "filename", filename, NULL); +} + +/** + * e_module_get_filename: + * @module: an #EModule + * + * Returns the filename of the shared library for @module. The + * string is owned by @module and should not be modified or freed. + * + * Returns: the filename for @module + **/ +const gchar * +e_module_get_filename (EModule *module) +{ + g_return_val_if_fail (E_IS_MODULE (module), NULL); + + return module->priv->filename; +} + +/** + * e_module_load_all_in_directory: + * @dirname: pathname for a directory containing modules to load + * + * Loads all the modules in the specified directory into memory. If + * you want to unload them (enabling on-demand loading) you must call + * g_type_module_unuse() on all the modules. Free the returned list + * with g_list_free(). + * + * Returns: a list of #EModules loaded from @dirname + **/ +GList * +e_module_load_all_in_directory (const gchar *dirname) +{ + GDir *dir; + const gchar *basename; + GList *loaded_modules = NULL; + GError *error = NULL; + + g_return_val_if_fail (dirname != NULL, NULL); + + if (!g_module_supported ()) + return NULL; + + dir = g_dir_open (dirname, 0, &error); + if (dir == NULL) { + g_warning ("%s", error->message); + g_error_free (error); + return NULL; + } + + while ((basename = g_dir_read_name (dir)) != NULL) { + EModule *module; + gchar *filename; + + if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX)) + continue; + + filename = g_build_filename (dirname, basename, NULL); + + module = e_module_new (filename); + + if (!g_type_module_use (G_TYPE_MODULE (module))) { + g_printerr ("Failed to load module: %s\n", filename); + g_object_unref (module); + g_free (filename); + continue; + } + + g_free (filename); + + loaded_modules = g_list_prepend (loaded_modules, module); + } + + g_dir_close (dir); + + return loaded_modules; +} diff --git a/e-util/e-module.h b/e-util/e-module.h new file mode 100644 index 0000000000..022769dc1c --- /dev/null +++ b/e-util/e-module.h @@ -0,0 +1,81 @@ +/* + * e-module.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/** + * SECTION: e-module + * @short_description: generic module loader + * @include: e-util/e-module.h + **/ + +#ifndef E_MODULE_H +#define E_MODULE_H + +#include <gmodule.h> +#include <glib-object.h> + +/* Standard GObject macros */ +#define E_TYPE_MODULE \ + (e_module_get_type ()) +#define E_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MODULE, EModule)) +#define E_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MODULE, EModuleClass)) +#define E_IS_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MODULE)) +#define E_IS_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MODULE)) +#define E_MODULE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MODULE, EModuleClass)) + +G_BEGIN_DECLS + +typedef struct _EModule EModule; +typedef struct _EModuleClass EModuleClass; +typedef struct _EModulePrivate EModulePrivate; + +/** + * EModule: + * + * Contains only private data that should be read and manipulated using the + * functions below. + **/ +struct _EModule { + GTypeModule parent; + EModulePrivate *priv; +}; + +struct _EModuleClass { + GTypeModuleClass parent_class; +}; + +GType e_module_get_type (void); +EModule * e_module_new (const gchar *filename); +const gchar * e_module_get_filename (EModule *module); +GList * e_module_load_all_in_directory (const gchar *dirname); + +G_END_DECLS + +#endif /* E_MODULE_H */ diff --git a/e-util/e-non-intrusive-error-dialog.c b/e-util/e-non-intrusive-error-dialog.c index 070c1e9bef..5fd98cacd2 100644 --- a/e-util/e-non-intrusive-error-dialog.c +++ b/e-util/e-non-intrusive-error-dialog.c @@ -305,4 +305,3 @@ eni_show_logger(ELogger *logger, GtkWidget *top,const char *error_timeout_path, gtk_widget_show_all (window); } - diff --git a/e-util/e-non-intrusive-error-dialog.h b/e-util/e-non-intrusive-error-dialog.h index e801d47a52..159242c0fa 100644 --- a/e-util/e-non-intrusive-error-dialog.h +++ b/e-util/e-non-intrusive-error-dialog.h @@ -38,7 +38,7 @@ struct _log_data { GdkPixbuf *pbuf; } ldata [] = { { E_LOG_ERROR, N_("Error"), N_("Errors"), GTK_STOCK_DIALOG_ERROR }, - { E_LOG_WARNINGS, N_("Warning"), N_("Warnings and Errors"), GTK_STOCK_DIALOG_WARNING }, + { E_LOG_WARNING, N_("Warning"), N_("Warnings and Errors"), GTK_STOCK_DIALOG_WARNING }, { E_LOG_DEBUG, N_("Debug"), N_("Error, Warnings and Debug messages"), GTK_STOCK_DIALOG_INFO } }; diff --git a/e-util/e-plugin-ui.c b/e-util/e-plugin-ui.c index c3ee13fe60..099efd0d65 100644 --- a/e-util/e-plugin-ui.c +++ b/e-util/e-plugin-ui.c @@ -25,7 +25,6 @@ #define E_PLUGIN_UI_INIT_FUNC "e_plugin_ui_init" #define E_PLUGIN_UI_HOOK_CLASS_ID "org.gnome.evolution.ui:1.0" -#define E_PLUGIN_UI_MANAGER_ID_KEY "e-plugin-ui-manager-id" struct _EPluginUIHookPrivate { @@ -33,9 +32,11 @@ struct _EPluginUIHookPrivate { * * For example: * - * <ui-manager id="org.gnome.evolution.sample"> - * ... UI definition ... - * </ui-manager> + * <hook class="org.gnome.evolution.ui:1.0"> + * <ui-manager id="org.gnome.evolution.sample"> + * ... UI definition ... + * </ui-manager> + * </hook> * * Results in: * @@ -49,197 +50,310 @@ struct _EPluginUIHookPrivate { * optional. */ GHashTable *ui_definitions; + + /* The registry is the heart of EPluginUI. It tracks GtkUIManager + * instances, GtkUIManager IDs, and UI merge IDs as a hash table of + * hash tables: + * + * GtkUIManager instance -> GtkUIManager ID -> UI Merge ID + * + * A GtkUIManager instance and ID form a unique key for looking up + * UI merge IDs. The reason both are needed is because the same + * GtkUIManager instance and be registered under multiple IDs. + * + * This is done primarily to support shell views, which share a + * common GtkUIManager instance for a particular shell window. + * Each shell view registers the same GtkUIManager instance under + * a unique ID: + * + * "org.gnome.evolution.mail" } + * "org.gnome.evolution.contacts" } aliases for a common + * "org.gnome.evolution.calendar" } GtkUIManager instance + * "org.gnome.evolution.memos" } + * "org.gnome.evolution.tasks" } + * + * Note: The shell window also registers the same GtkUIManager + * instance as "org.gnome.evolution.shell". + * + * This way, plugins that extend a shell view's UI will follow the + * merging and unmerging of the shell view automatically. + * + * The presence or absence of GtkUIManager IDs in the registry is + * significant. Presence of a (instance, ID) pair indicates that + * UI manager is active, absence indicates inactive. Furthermore, + * a non-zero merge ID for an active UI manager indicates the + * plugin is enabled. Zero indicates disabled. + * + * Here's a quick scenario to illustrate: + * + * Suppose we have a plugin that extends the mail shell view UI. + * Its EPlugin definition file has this section: + * + * <hook class="org.gnome.evolution.ui:1.0"> + * <ui-manager id="org.gnome.evolution.mail"> + * ... UI definition ... + * </ui-manager> + * </hook> + * + * The plugin is enabled and the active shell view is "mail". + * Let "ManagerA" denote the common GtkUIManager instance for + * this shell window. Here's what happens to the registry as + * the user performs various actions; + * + * - Initial State Merge ID + * V + * { "ManagerA", { "org.gnome.evolution.mail", 3 } } + * + * - User Disables the Plugin + * + * { "ManagerA", { "org.gnome.evolution.mail", 0 } } + * + * - User Enables the Plugin + * + * { "ManagerA", { "org.gnome.evolution.mail", 4 } } + * + * - User Switches to Calendar View + * + * { "ManagerA", { } } + * + * - User Disables the Plugin + * + * { "ManagerA", { } } + * + * - User Switches to Mail View + * + * { "ManagerA", { "org.gnome.evolution.mail", 0 } } + * + * - User Enables the Plugin + * + * { "ManagerA", { "org.gnome.evolution.mail", 5 } } + */ + GHashTable *registry; }; -/* The registry is a hash table of hash tables. It maps - * - * EPluginUIHook instance --> GtkUIManager instance --> UI merge id - * - * GtkUIManager instances are automatically removed when finalized. - */ -static GHashTable *registry; static gpointer parent_class; static void -plugin_ui_registry_remove (EPluginUIHook *hook, - GtkUIManager *ui_manager) +plugin_ui_hook_unregister_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager) { - GHashTable *hash_table; + GHashTable *registry; /* Note: Manager may already be finalized. */ - - hash_table = g_hash_table_lookup (registry, hook); - g_return_if_fail (hash_table != NULL); - - g_hash_table_remove (hash_table, ui_manager); - if (g_hash_table_size (hash_table) == 0) - g_hash_table_remove (registry, hook); + registry = hook->priv->registry; + g_hash_table_remove (registry, ui_manager); } static void -plugin_ui_registry_insert (EPluginUIHook *hook, - GtkUIManager *ui_manager, - guint merge_id) +plugin_ui_hook_register_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager, + gpointer user_data) { + EPlugin *plugin; + EPluginUIInitFunc func; + GHashTable *registry; GHashTable *hash_table; - hash_table = g_hash_table_lookup (registry, hook); - if (hash_table == NULL) { - hash_table = g_hash_table_new (g_direct_hash, g_direct_equal); - g_hash_table_insert (registry, hook, hash_table); - } + plugin = ((EPluginHook *) hook)->plugin; + func = e_plugin_get_symbol (plugin, E_PLUGIN_UI_INIT_FUNC); + + /* Pass the manager and user_data to the plugin's e_plugin_ui_init() + * function (if it defined one). The plugin should install whatever + * GtkActions and GtkActionGroups are neccessary to implement the + * action names in its UI definition. */ + if (func != NULL && !func (ui_manager, user_data)) + return; g_object_weak_ref ( G_OBJECT (ui_manager), (GWeakNotify) - plugin_ui_registry_remove, hook); + plugin_ui_hook_unregister_manager, hook); - g_hash_table_insert ( - hash_table, ui_manager, GUINT_TO_POINTER (merge_id)); + registry = hook->priv->registry; + hash_table = g_hash_table_lookup (registry, ui_manager); + + if (hash_table == NULL) { + hash_table = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + g_hash_table_insert (registry, ui_manager, hash_table); + } } -/* Helper for plugin_ui_hook_merge_ui() */ -static void -plugin_ui_hook_merge_foreach (GtkUIManager *ui_manager, - const gchar *ui_definition, - GHashTable *hash_table) +static guint +plugin_ui_hook_merge_ui (EPluginUIHook *hook, + GtkUIManager *ui_manager, + const gchar *id) { + GHashTable *hash_table; + const gchar *ui_definition; guint merge_id; GError *error = NULL; - /* Merge the UI definition into the manager. */ + hash_table = hook->priv->ui_definitions; + ui_definition = g_hash_table_lookup (hash_table, id); + g_return_val_if_fail (ui_definition != NULL, 0); + merge_id = gtk_ui_manager_add_ui_from_string ( ui_manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (ui_manager); + if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); } - /* Merge ID will be 0 on error, which is what we want. */ - g_hash_table_insert ( - hash_table, ui_manager, GUINT_TO_POINTER (merge_id)); + return merge_id; } static void -plugin_ui_hook_merge_ui (EPluginUIHook *hook) +plugin_ui_enable_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager, + const gchar *id) { - GHashTable *old_merge_ids; - GHashTable *new_merge_ids; - GHashTable *intermediate; + GHashTable *hash_table; + GHashTable *ui_definitions; GList *keys; - old_merge_ids = g_hash_table_lookup (registry, hook); - if (old_merge_ids == NULL) - return; + hash_table = hook->priv->registry; + hash_table = g_hash_table_lookup (hash_table, ui_manager); - /* The GtkUIManager instances and UI definitions live in separate - * tables, so we need to build an intermediate table that we can - * easily iterate over. */ - keys = g_hash_table_get_keys (old_merge_ids); - intermediate = g_hash_table_new (g_direct_hash, g_direct_equal); + if (hash_table == NULL) + return; - while (keys != NULL) { - GtkUIManager *ui_manager = keys->data; - gchar *ui_definition; + if (id != NULL) + keys = g_list_prepend (NULL, (gpointer) id); + else + keys = g_hash_table_get_keys (hash_table); - ui_definition = g_hash_table_lookup ( - hook->priv->ui_definitions, - e_plugin_ui_get_manager_id (ui_manager)); + ui_definitions = hook->priv->ui_definitions; - g_hash_table_insert (intermediate, ui_manager, ui_definition); + while (keys != NULL) { + guint merge_id; + gpointer data; + id = keys->data; keys = g_list_delete_link (keys, keys); - } - new_merge_ids = g_hash_table_new (g_direct_hash, g_direct_equal); + if (g_hash_table_lookup (ui_definitions, id) == NULL) + continue; + + data = g_hash_table_lookup (hash_table, id); + merge_id = GPOINTER_TO_UINT (data); - g_hash_table_foreach ( - intermediate, (GHFunc) - plugin_ui_hook_merge_foreach, new_merge_ids); + if (merge_id > 0) + continue; - g_hash_table_insert (registry, hook, new_merge_ids); + if (((EPluginHook *) hook)->plugin->enabled) + merge_id = plugin_ui_hook_merge_ui ( + hook, ui_manager, id); - g_hash_table_destroy (intermediate); + /* Merge ID will be 0 on error, which is what we want. */ + data = GUINT_TO_POINTER (merge_id); + g_hash_table_insert (hash_table, g_strdup (id), data); + } } -/* Helper for plugin_ui_hook_unmerge_ui() */ static void -plugin_ui_hook_unmerge_foreach (GtkUIManager *ui_manager, - gpointer value, - GHashTable *hash_table) +plugin_ui_disable_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager, + const gchar *id, + gboolean remove) { - guint merge_id; + GHashTable *hash_table; + GHashTable *ui_definitions; + GList *keys; + + hash_table = hook->priv->registry; + hash_table = g_hash_table_lookup (hash_table, ui_manager); + + if (hash_table == NULL) + return; + + if (id != NULL) + keys = g_list_prepend (NULL, (gpointer) id); + else + keys = g_hash_table_get_keys (hash_table); + + ui_definitions = hook->priv->ui_definitions; + + while (keys != NULL) { + guint merge_id; + gpointer data; - merge_id = GPOINTER_TO_UINT (value); - gtk_ui_manager_remove_ui (ui_manager, merge_id); + id = keys->data; + keys = g_list_delete_link (keys, keys); + + if (g_hash_table_lookup (ui_definitions, id) == NULL) + continue; - g_hash_table_insert (hash_table, ui_manager, GUINT_TO_POINTER (0)); + data = g_hash_table_lookup (hash_table, id); + merge_id = GPOINTER_TO_UINT (data); + + /* Merge ID could be 0 if the plugin is disabled. */ + if (merge_id > 0) + gtk_ui_manager_remove_ui (ui_manager, merge_id); + + if (remove) + g_hash_table_remove (hash_table, id); + else + g_hash_table_insert (hash_table, g_strdup (id), NULL); + } } static void -plugin_ui_hook_unmerge_ui (EPluginUIHook *hook) +plugin_ui_enable_hook (EPluginUIHook *hook) { - GHashTable *old_merge_ids; - GHashTable *new_merge_ids; - - old_merge_ids = g_hash_table_lookup (registry, hook); - if (old_merge_ids == NULL) - return; + GHashTable *hash_table; + GHashTableIter iter; + gpointer key; - new_merge_ids = g_hash_table_new (g_direct_hash, g_direct_equal); + /* Enable all GtkUIManagers for this hook. */ - g_hash_table_foreach ( - old_merge_ids, (GHFunc) - plugin_ui_hook_unmerge_foreach, new_merge_ids); + hash_table = hook->priv->registry; + g_hash_table_iter_init (&iter, hash_table); - g_hash_table_insert (registry, hook, new_merge_ids); + while (g_hash_table_iter_next (&iter, &key, NULL)) { + GtkUIManager *ui_manager = key; + plugin_ui_enable_manager (hook, ui_manager, NULL); + } } static void -plugin_ui_hook_register_manager (EPluginUIHook *hook, - GtkUIManager *ui_manager, - const gchar *ui_definition, - gpointer user_data) +plugin_ui_disable_hook (EPluginUIHook *hook) { - EPlugin *plugin; - EPluginUIInitFunc func; - guint merge_id = 0; + GHashTable *hash_table; + GHashTableIter iter; + gpointer key; - plugin = ((EPluginHook *) hook)->plugin; - func = e_plugin_get_symbol (plugin, E_PLUGIN_UI_INIT_FUNC); + /* Disable all GtkUIManagers for this hook. */ - /* Pass the manager and user_data to the plugin's e_plugin_ui_init() - * function (if it defined one). The plugin should install whatever - * GtkActions and GtkActionGroups are neccessary to implement the - * action names in its UI definition. */ - if (func != NULL && !func (ui_manager, user_data)) - return; + hash_table = hook->priv->registry; + g_hash_table_iter_init (&iter, hash_table); - if (plugin->enabled) { - GError *error = NULL; - - /* Merge the UI definition into the manager. */ - merge_id = gtk_ui_manager_add_ui_from_string ( - ui_manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (ui_manager); - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } + while (g_hash_table_iter_next (&iter, &key, NULL)) { + GtkUIManager *ui_manager = key; + plugin_ui_disable_manager (hook, ui_manager, NULL, FALSE); } - - /* Save merge ID's for later use. */ - plugin_ui_registry_insert (hook, ui_manager, merge_id); } static void plugin_ui_hook_finalize (GObject *object) { EPluginUIHookPrivate *priv; + GHashTableIter iter; + gpointer ui_manager; priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (object); + /* Remove weak reference callbacks to GtkUIManagers. */ + g_hash_table_iter_init (&iter, priv->registry); + while (g_hash_table_iter_next (&iter, &ui_manager, NULL)) + g_object_weak_unref ( + G_OBJECT (ui_manager), (GWeakNotify) + plugin_ui_hook_unregister_manager, object); + g_hash_table_destroy (priv->ui_definitions); + g_hash_table_destroy (priv->registry); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); @@ -300,9 +414,9 @@ plugin_ui_hook_enable (EPluginHook *hook, gint state) { if (state) - plugin_ui_hook_merge_ui (E_PLUGIN_UI_HOOK (hook)); + plugin_ui_enable_hook (E_PLUGIN_UI_HOOK (hook)); else - plugin_ui_hook_unmerge_ui (E_PLUGIN_UI_HOOK (hook)); + plugin_ui_disable_hook (E_PLUGIN_UI_HOOK (hook)); } static void @@ -321,25 +435,24 @@ plugin_ui_hook_class_init (EPluginUIHookClass *class) plugin_hook_class->id = E_PLUGIN_UI_HOOK_CLASS_ID; plugin_hook_class->construct = plugin_ui_hook_construct; plugin_hook_class->enable = plugin_ui_hook_enable; - - registry = g_hash_table_new_full ( - g_direct_hash, g_direct_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) g_hash_table_destroy); } static void plugin_ui_hook_init (EPluginUIHook *hook) { GHashTable *ui_definitions; + GHashTable *registry; ui_definitions = g_hash_table_new_full ( g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); + registry = g_hash_table_new (g_direct_hash, g_direct_equal); + hook->priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (hook); hook->priv->ui_definitions = ui_definitions; + hook->priv->registry = registry; } GType @@ -369,17 +482,14 @@ e_plugin_ui_hook_get_type (void) } void -e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *ui_manager, +e_plugin_ui_register_manager (GtkUIManager *ui_manager, + const gchar *id, gpointer user_data) { - const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY; GSList *plugin_list; - g_return_if_fail (id != NULL); g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - - g_object_set_data (G_OBJECT (ui_manager), key, (gpointer) id); + g_return_if_fail (id != NULL); /* Loop over all installed plugins. */ plugin_list = e_plugin_list_plugins (); @@ -387,36 +497,84 @@ e_plugin_ui_register_manager (const gchar *id, EPlugin *plugin = plugin_list->data; GSList *iter; + plugin_list = g_slist_next (plugin_list); + /* Look for hooks of type EPluginUIHook. */ for (iter = plugin->hooks; iter != NULL; iter = iter->next) { EPluginUIHook *hook = iter->data; - const gchar *ui_definition; + GHashTable *hash_table; if (!E_IS_PLUGIN_UI_HOOK (hook)) continue; + hash_table = hook->priv->ui_definitions; + /* Check if the hook has a UI definition * for the GtkUIManager being registered. */ - ui_definition = g_hash_table_lookup ( - hook->priv->ui_definitions, id); - if (ui_definition == NULL) + if (g_hash_table_lookup (hash_table, id) == NULL) continue; /* Register the manager with the hook. */ plugin_ui_hook_register_manager ( - hook, ui_manager, ui_definition, user_data); + hook, ui_manager, user_data); } + } +} + +void +e_plugin_ui_enable_manager (GtkUIManager *ui_manager, + const gchar *id) +{ + GSList *plugin_list; + + g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); + g_return_if_fail (id != NULL); + + /* Loop over all installed plugins. */ + plugin_list = e_plugin_list_plugins (); + while (plugin_list != NULL) { + EPlugin *plugin = plugin_list->data; + GSList *iter; plugin_list = g_slist_next (plugin_list); + + /* Look for hooks of type EPluginUIHook. */ + for (iter = plugin->hooks; iter != NULL; iter = iter->next) { + EPluginUIHook *hook = iter->data; + + if (!E_IS_PLUGIN_UI_HOOK (hook)) + continue; + + plugin_ui_enable_manager (hook, ui_manager, id); + } } } -const gchar * -e_plugin_ui_get_manager_id (GtkUIManager *ui_manager) +void +e_plugin_ui_disable_manager (GtkUIManager *ui_manager, + const gchar *id) { - const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY; + GSList *plugin_list; + + g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); + g_return_if_fail (id != NULL); + + /* Loop over all installed plugins. */ + plugin_list = e_plugin_list_plugins (); + while (plugin_list != NULL) { + EPlugin *plugin = plugin_list->data; + GSList *iter; - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); + plugin_list = g_slist_next (plugin_list); + + /* Look for hooks of type EPluginUIHook. */ + for (iter = plugin->hooks; iter != NULL; iter = iter->next) { + EPluginUIHook *hook = iter->data; - return g_object_get_data (G_OBJECT (ui_manager), key); + if (!E_IS_PLUGIN_UI_HOOK (hook)) + continue; + + plugin_ui_disable_manager (hook, ui_manager, id, TRUE); + } + } } diff --git a/e-util/e-plugin-ui.h b/e-util/e-plugin-ui.h index b8e795c4c4..74d5bdc092 100644 --- a/e-util/e-plugin-ui.h +++ b/e-util/e-plugin-ui.h @@ -62,10 +62,13 @@ typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *ui_manager, GType e_plugin_ui_hook_get_type (void); -void e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *ui_manager, +void e_plugin_ui_register_manager (GtkUIManager *ui_manager, + const gchar *id, gpointer user_data); -const gchar * e_plugin_ui_get_manager_id (GtkUIManager *ui_manager); +void e_plugin_ui_enable_manager (GtkUIManager *ui_manager, + const gchar *id); +void e_plugin_ui_disable_manager (GtkUIManager *ui_manager, + const gchar *id); G_END_DECLS diff --git a/e-util/e-signature-utils.c b/e-util/e-signature-utils.c new file mode 100644 index 0000000000..0114ce6e06 --- /dev/null +++ b/e-util/e-signature-utils.c @@ -0,0 +1,347 @@ +/* + * e-signature-utils.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#include "e-signature-utils.h" + +#include <errno.h> +#include <glib/gstdio.h> +#include <gconf/gconf-client.h> +#include <camel/camel-stream.h> +#include <camel/camel-stream-fs.h> +#include <camel/camel-stream-mem.h> +#include <camel/camel-stream-filter.h> +#include <camel/camel-mime-filter-charset.h> +#include <camel/camel-mime-filter-tohtml.h> + +#ifndef G_OS_WIN32 +#include <sys/wait.h> +#endif + +#include "e-util/e-util.h" + +static ESignatureList *global_signature_list; + +ESignatureList * +e_get_signature_list (void) +{ + if (G_UNLIKELY (global_signature_list == NULL)) { + GConfClient *client; + + client = gconf_client_get_default (); + global_signature_list = e_signature_list_new (client); + g_object_unref (client); + } + + g_return_val_if_fail (global_signature_list != NULL, NULL); + + return global_signature_list; +} + +ESignature * +e_get_signature_by_name (const gchar *name) +{ + ESignatureList *signature_list; + const ESignature *signature; + e_signature_find_t find; + + g_return_val_if_fail (name != NULL, NULL); + + find = E_SIGNATURE_FIND_NAME; + signature_list = e_get_signature_list (); + signature = e_signature_list_find (signature_list, find, name); + + /* XXX ESignatureList misuses const. */ + return (ESignature *) signature; +} + +ESignature * +e_get_signature_by_uid (const gchar *uid) +{ + ESignatureList *signature_list; + const ESignature *signature; + e_signature_find_t find; + + g_return_val_if_fail (uid != NULL, NULL); + + find = E_SIGNATURE_FIND_UID; + signature_list = e_get_signature_list (); + signature = e_signature_list_find (signature_list, find, uid); + + /* XXX ESignatureList misuses const. */ + return (ESignature *) signature; +} + +gchar * +e_create_signature_file (GError **error) +{ + const gchar *data_dir; + gchar basename[32]; + gchar *filename; + gchar *pathname; + gint32 ii; + + data_dir = e_get_user_data_dir (); + pathname = g_build_filename (data_dir, "signatures", NULL); + filename = NULL; + + if (g_mkdir_with_parents (pathname, 0700) < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", pathname, g_strerror (errno)); + g_free (pathname); + return NULL; + } + + for (ii = 0; ii < G_MAXINT32; ii++) { + + g_snprintf ( + basename, sizeof (basename), + "signature-%" G_GINT32_FORMAT, ii); + + g_free (filename); + filename = g_build_filename (pathname, basename, NULL); + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + gint fd; + + fd = g_creat (filename, 0600); + if (fd >= 0) { + close (fd); + break; + } + + /* If we failed once we're probably going + * to continue failing, so just give up. */ + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", filename, g_strerror (errno)); + g_free (filename); + filename = NULL; + break; + } + } + + /* If there are actually G_MAXINT32 signature files, the + * most recent signature file we be overwritten. Sorry. */ + + return filename; +} + +gchar * +e_read_signature_file (ESignature *signature, + gboolean convert_to_html, + GError **error) +{ + CamelStream *input_stream; + CamelStream *output_stream; + GByteArray *buffer; + gchar *content; + gsize length; + gint fd; + + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + fd = g_open (signature->filename, O_RDONLY, 0); + if (fd < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", signature->filename, + g_strerror (errno)); + return NULL; + } + + input_stream = camel_stream_fs_new_with_fd (fd); + + if (!signature->html && convert_to_html) { + CamelStreamFilter *filtered_stream; + CamelMimeFilter *filter; + gint32 flags; + + filtered_stream = + camel_stream_filter_new_with_stream (input_stream); + camel_object_unref (input_stream); + + flags = + CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES | + CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; + filter = camel_mime_filter_tohtml_new (flags, 0); + camel_stream_filter_add (filtered_stream, filter); + camel_object_unref (filter); + + input_stream = (CamelStream *) filtered_stream; + } + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + camel_stream_write_to_stream (input_stream, output_stream); + camel_object_unref (output_stream); + camel_object_unref (input_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guint8 *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signatures are saved as UTF-8, but we still need to check that + * the signature is valid UTF-8 because the user may be opening + * a signature file that is in his/her locale character set. If + * it's not in UTF-8 then try converting from the current locale. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + utf8 = g_locale_to_utf8 (content, length, NULL, NULL, error); + g_free (content); + content = utf8; + } + + return content; +} + +gchar * +e_run_signature_script (const gchar *filename) +{ + /* FIXME Make this cross-platform, prefer GLib functions over + * POSIX, and report errors via GError instead of dumping + * messages to the terminal where users won't see them. */ + +#ifndef G_OS_WIN32 + gint in_fds[2]; + pid_t pid; + + g_return_val_if_fail (filename != NULL, NULL); + + if (pipe (in_fds) == -1) { + g_warning ( + "Failed to create pipe to '%s': %s", + filename, g_strerror (errno)); + return NULL; + } + + pid = fork (); + + /* Child Process */ + if (pid == 0) { + gint maxfd, ii; + + close (in_fds[0]); + if (dup2 (in_fds[1], STDOUT_FILENO) < 0) + _exit (255); + close (in_fds[1]); + + setsid (); + + maxfd = sysconf (_SC_OPEN_MAX); + for (ii = 3; ii < maxfd; ii++) { + if (ii == STDIN_FILENO) + continue; + if (ii == STDOUT_FILENO) + continue; + if (ii == STDERR_FILENO) + continue; + fcntl (ii, F_SETFD, FD_CLOEXEC); + } + + execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL); + + g_warning ( + "Could not execute '%s': %s", + filename, g_strerror (errno)); + + _exit (255); + + /* Parent Process */ + } else if (pid > 0) { + CamelStream *output_stream; + CamelStream *input_stream; + GByteArray *buffer; + gchar *content; + gsize length; + gint result; + gint status; + + close (in_fds[1]); + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + + input_stream = camel_stream_fs_new_with_fd (in_fds[0]); + camel_stream_write_to_stream (input_stream, output_stream); + camel_object_unref (input_stream); + + camel_object_unref (output_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guchar *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signature scripts are supposed to generate UTF-8 content, + * but because users are known to never read the manual, we + * try to do our best if the content isn't valid UTF-8 by + * assuming that the content is in the user's locale + * character set. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + /* XXX Should pass a GError here. */ + utf8 = g_locale_to_utf8 ( + content, length, NULL, NULL, NULL); + g_free (content); + content = utf8; + } + + /* Wait for the script process to terminate. */ + result = waitpid (pid, &status, 0); + + if (result == -1 && errno == EINTR) { + /* Child process is hanging... */ + kill (pid, SIGTERM); + sleep (1); + result = waitpid (pid, &status, WNOHANG); + if (result == 0) { + /* ...still hanging, set phasers to KILL. */ + kill (pid, SIGKILL); + sleep (1); + result = waitpid (pid, &status, WNOHANG); + } + } + + return content; + + /* Forking Failed */ + } else { + g_warning ( + "Failed to create child process '%s': %s", + filename, g_strerror (errno)); + close (in_fds[0]); + close (in_fds[1]); + } +#endif + + return NULL; +} diff --git a/e-util/e-corba-utils.h b/e-util/e-signature-utils.h index 979237929d..41472f45d0 100644 --- a/e-util/e-corba-utils.h +++ b/e-util/e-signature-utils.h @@ -1,4 +1,6 @@ /* + * e-signature-utils.h + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -12,20 +14,27 @@ * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see <http://www.gnu.org/licenses/> * - * - * Authors: - * Ettore Perazzoli <ettore@ximian.com> - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ -#ifndef E_CORBA_UTILS_H -#define E_CORBA_UTILS_H +#ifndef E_SIGNATURE_UTILS_H +#define E_SIGNATURE_UTILS_H + +#include <gtk/gtk.h> +#include <e-util/e-signature.h> +#include <e-util/e-signature-list.h> + +G_BEGIN_DECLS -#include <orbit/orbit.h> +ESignatureList *e_get_signature_list (void); +ESignature * e_get_signature_by_name (const gchar *name); +ESignature * e_get_signature_by_uid (const gchar *uid); +gchar * e_create_signature_file (GError **error); +gchar * e_read_signature_file (ESignature *signature, + gboolean convert_to_html, + GError **error); +gchar * e_run_signature_script (const gchar *filename); -const CORBA_char *e_safe_corba_string (const char *s); -CORBA_char *e_safe_corba_string_dup (const char *s); +G_END_DECLS -#endif +#endif /* E_SIGNATURE_UTILS_H */ diff --git a/e-util/e-unicode.c b/e-util/e-unicode.c new file mode 100644 index 0000000000..9d660b6600 --- /dev/null +++ b/e-util/e-unicode.c @@ -0,0 +1,2052 @@ +/* + * e-unicode.c - utf-8 support functions for gal + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Lauris Kaplinski <lauris@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/* + * TODO: Break simple ligatures in e_utf8_strstrcasedecomp + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <iconv.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <libxml/xmlmemory.h> + +#include <camel/camel-iconv.h> + +#include <glib/gi18n.h> +#include "e-unicode.h" + +#define d(x) + +#define FONT_TESTING +#define MAX_DECOMP 8 + +static gint e_canonical_decomposition (gunichar ch, gunichar * buf); +static gunichar e_stripped_char (gunichar ch); + +/* FIXME: this has not been ported fully yet - non ASCII people beware. */ + +/* + * This my favourite + * + * strstr doing case insensitive, decomposing search + * + * Lauris + */ + +const gchar * +e_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle) +{ + gunichar *nuni; + gunichar unival; + gint nlen; + const gchar *o, *p; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + if (strlen (haystack) == 0) return NULL; + + nuni = alloca (sizeof (gunichar) * strlen (needle)); + + nlen = 0; + for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + gint sc; + sc = e_stripped_char (unival); + if (sc) { + nuni[nlen++] = sc; + } + } + /* NULL means there was illegal utf-8 sequence */ + if (!p) return NULL; + /* If everything is correct, we have decomposed, lowercase, stripped needle */ + if (nlen < 1) return haystack; + + o = haystack; + for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + gint sc; + sc = e_stripped_char (unival); + if (sc) { + /* We have valid stripped char */ + if (sc == nuni[0]) { + const gchar *q = p; + gint npos = 1; + while (npos < nlen) { + q = e_unicode_get_utf8 (q, &unival); + if (!q || !unival) return NULL; + sc = e_stripped_char (unival); + if ((!sc) || (sc != nuni[npos])) break; + npos++; + } + if (npos == nlen) { + return o; + } + } + } + o = p; + } + + return NULL; +} + +const gchar * +e_utf8_strstrcase (const gchar *haystack, const gchar *needle) +{ + gunichar *nuni; + gunichar unival; + gint nlen; + const gchar *o, *p; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + if (strlen (haystack) == 0) return NULL; + + nuni = alloca (sizeof (gunichar) * strlen (needle)); + + nlen = 0; + for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + nuni[nlen++] = g_unichar_tolower (unival); + } + /* NULL means there was illegal utf-8 sequence */ + if (!p) return NULL; + + o = haystack; + for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + gint sc; + sc = g_unichar_tolower (unival); + /* We have valid stripped char */ + if (sc == nuni[0]) { + const gchar *q = p; + gint npos = 1; + while (npos < nlen) { + q = e_unicode_get_utf8 (q, &unival); + if (!q || !unival) return NULL; + sc = g_unichar_tolower (unival); + if (sc != nuni[npos]) break; + npos++; + } + if (npos == nlen) { + return o; + } + } + o = p; + } + + return NULL; +} + +#if 0 +const gchar * +e_utf8_strstrcase (const gchar *haystack, const gchar *needle) +{ + gchar *p; + gunichar *huni, *nuni; + gunichar unival; + gint hlen, nlen, hp, np; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + + huni = alloca (sizeof (gunichar) * strlen (haystack)); + + for (hlen = 0, p = e_unicode_get_utf8 (haystack, &unival); p && unival; hlen++, p = e_unicode_get_utf8 (p, &unival)) { + huni[hlen] = g_unichar_tolower (unival); + } + + if (!p) return NULL; + if (hlen == 0) return NULL; + + nuni = alloca (sizeof (gunichar) * strlen (needle)); + + for (nlen = 0, p = e_unicode_get_utf8 (needle, &unival); p && unival; nlen++, p = e_unicode_get_utf8 (p, &unival)) { + nuni[nlen] = g_unichar_tolower (unival); + } + + if (!p) return NULL; + if (nlen == 0) return NULL; + + if (hlen < nlen) return NULL; + + for (hp = 0; hp <= hlen - nlen; hp++) { + for (np = 0; np < nlen; np++) { + if (huni[hp + np] != nuni[np]) break; + } + if (np == nlen) return haystack + unicode_offset_to_index (haystack, hp); + } + + return NULL; +} +#endif + +gchar * +e_utf8_from_gtk_event_key (GtkWidget *widget, guint keyval, const gchar *string) +{ + gint unival; + gchar *utf; + gint unilen; + + if (keyval == GDK_VoidSymbol) { + utf = e_utf8_from_locale_string (string); + } else { + unival = gdk_keyval_to_unicode (keyval); + + if (unival < ' ') return NULL; + + utf = g_new (gchar, 7); + + unilen = e_unichar_to_utf8 (unival, utf); + + utf[unilen] = '\0'; + } + + return utf; +} + +gchar * +e_utf8_from_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) +{ + char *new, *ob; + const char *ib; + size_t ibl, obl; + + if (!string) return NULL; + + if (ic == (iconv_t) -1) { + gint i; + /* iso-8859-1 */ + ib = (char *) string; + new = ob = (char *)g_new (unsigned char, bytes * 2 + 1); + for (i = 0; i < (bytes); i ++) { + ob += e_unichar_to_utf8 (ib[i], ob); + } + *ob = '\0'; + return new; + } + + ib = string; + ibl = bytes; + new = ob = g_new (gchar, ibl * 6 + 1); + obl = ibl * 6; + + while (ibl > 0) { + camel_iconv (ic, &ib, &ibl, &ob, &obl); + if (ibl > 0) { + gint len; + if ((*ib & 0x80) == 0x00) len = 1; + else if ((*ib &0xe0) == 0xc0) len = 2; + else if ((*ib &0xf0) == 0xe0) len = 3; + else if ((*ib &0xf8) == 0xf0) len = 4; + else { + g_warning ("Invalid UTF-8 sequence"); + break; + } + ib += len; + ibl = bytes - (ib - string); + if (ibl > bytes) ibl = 0; + *ob++ = '_'; + obl--; + } + } + + *ob = '\0'; + + return new; +} + +gchar * +e_utf8_from_iconv_string (iconv_t ic, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_from_iconv_string_sized (ic, string, strlen (string)); +} + +gchar * +e_utf8_to_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) +{ + char *new, *ob; + const char *ib; + size_t ibl, obl; + + if (!string) return NULL; + + if (ic == (iconv_t) -1) { + gint len; + const gchar *u; + gunichar uc; + + new = (char *)g_new (unsigned char, bytes * 4 + 1); + u = string; + len = 0; + + while ((u) && (u - string < bytes)) { + u = e_unicode_get_utf8 (u, &uc); + new[len++] = uc & 0xff; + } + new[len] = '\0'; + return new; + } + + ib = string; + ibl = bytes; + new = ob = g_new (char, ibl * 4 + 4); + obl = ibl * 4; + + while (ibl > 0) { + camel_iconv (ic, &ib, &ibl, &ob, &obl); + if (ibl > 0) { + gint len; + if ((*ib & 0x80) == 0x00) len = 1; + else if ((*ib &0xe0) == 0xc0) len = 2; + else if ((*ib &0xf0) == 0xe0) len = 3; + else if ((*ib &0xf8) == 0xf0) len = 4; + else { + g_warning ("Invalid UTF-8 sequence"); + break; + } + ib += len; + ibl = bytes - (ib - string); + if (ibl > bytes) ibl = 0; + + /* FIXME: this is wrong... what if the destination charset is 16 or 32 bit? */ + *ob++ = '_'; + obl--; + } + } + + /* Make sure to terminate with plenty of padding */ + memset (ob, 0, 4); + + return new; +} + +gchar * +e_utf8_to_iconv_string (iconv_t ic, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_to_iconv_string_sized (ic, string, strlen (string)); +} + +gchar * +e_utf8_from_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) +{ + iconv_t ic; + char *ret; + + if (!string) return NULL; + + ic = camel_iconv_open("utf-8", charset); + ret = e_utf8_from_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_from_charset_string (const gchar *charset, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_from_charset_string_sized (charset, string, strlen (string)); +} + +gchar * +e_utf8_to_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) +{ + iconv_t ic; + char *ret; + + if (!string) return NULL; + + ic = camel_iconv_open(charset, "utf-8"); + ret = e_utf8_to_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_to_charset_string (const gchar *charset, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_to_charset_string_sized (charset, string, strlen (string)); +} + +gchar * +e_utf8_from_locale_string_sized (const gchar *string, gint bytes) +{ + iconv_t ic; + char *ret; + + if (!string) return NULL; + + ic = camel_iconv_open("utf-8", camel_iconv_locale_charset()); + ret = e_utf8_from_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_from_locale_string (const gchar *string) +{ + if (!string) return NULL; + return e_utf8_from_locale_string_sized (string, strlen (string)); +} + +gchar * +e_utf8_to_locale_string_sized (const gchar *string, gint bytes) +{ + iconv_t ic; + char *ret; + + if (!string) return NULL; + + ic = camel_iconv_open(camel_iconv_locale_charset(), "utf-8"); + ret = e_utf8_to_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_to_locale_string (const gchar *string) +{ + if (!string) return NULL; + return e_utf8_to_locale_string_sized (string, strlen (string)); +} + +gboolean +e_utf8_is_ascii (const gchar *string) +{ + char c; + + g_return_val_if_fail (string != NULL, FALSE); + + for (; (c = *string); string++) { + if (c & 0x80) + return FALSE; + } + + return TRUE; +} + +gchar * +e_utf8_gtk_entry_get_text (GtkEntry *entry) +{ + return g_strdup (gtk_entry_get_text (entry)); +} + +gchar * +e_utf8_gtk_editable_get_text (GtkEditable *editable) +{ + return gtk_editable_get_chars (editable, 0, -1); +} + +gchar * +e_utf8_gtk_editable_get_chars (GtkEditable *editable, gint start, gint end) +{ + return gtk_editable_get_chars (editable, start, end); +} + +void +e_utf8_gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint length, gint *position) +{ + gtk_editable_insert_text (editable, text, length, position); +} + +void +e_utf8_gtk_editable_set_text (GtkEditable *editable, const gchar *text) +{ + int position; + + gtk_editable_delete_text(editable, 0, -1); + gtk_editable_insert_text (editable, text, strlen (text), &position); +} + +void +e_utf8_gtk_entry_set_text (GtkEntry *entry, const gchar *text) +{ + if (!text) + gtk_entry_set_text(entry, ""); + else + gtk_entry_set_text (entry, text); +} + +/* + * Translate \U+XXXX\ sequences to utf8 chars + */ + +gchar * +e_utf8_xml1_decode (const gchar *text) +{ + const guchar *c; + gchar *u, *d; + int len, s; + + g_return_val_if_fail (text != NULL, NULL); + + len = strlen (text)+1; + /* len * 2 is absolute maximum */ + u = d = g_malloc (len * 2); + + c = (guchar *)text; + s = 0; + while (s < len) { + if ((s <= (len - 8)) && + (c[s ] == '\\') && + (c[s + 1] == 'U' ) && + (c[s + 2] == '+' ) && + isxdigit (c[s + 3]) && + isxdigit (c[s + 4]) && + isxdigit (c[s + 5]) && + isxdigit (c[s + 6]) && + (c[s + 7] == '\\')) { + /* Valid \U+XXXX\ sequence */ + int unival; + unival = strtol ((char *)(c + s + 3), NULL, 16); + d += e_unichar_to_utf8 (unival, d); + s += 8; + } else if (c[s] > 127) { + /* fixme: We assume iso-8859-1 currently */ + d += e_unichar_to_utf8 (c[s], d); + s += 1; + } else { + *d++ = c[s++]; + } + } + *d++ = '\0'; + u = g_realloc (u, (d - u)); + + return u; +} + +gchar * +e_utf8_xml1_encode (const gchar *text) +{ + gchar *u, *d, *c; + unsigned int unival; + int len; + + g_return_val_if_fail (text != NULL, NULL); + + len = 0; + for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { + if ((unival >= 0x80) || (unival == '\\')) { + len += 8; + } else { + len += 1; + } + } + d = c = (char *)g_new (guchar, len + 1); + + for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { + if ((unival >= 0x80) || (unival == '\\')) { + *c++ = '\\'; + *c++ = 'U'; + *c++ = '+'; + c += sprintf (c, "%04x", unival); + *c++ = '\\'; + } else { + *c++ = unival; + } + } + *c = '\0'; + + return d; +} + +/** + * e_unichar_to_utf8: + * @c: a ISO10646 character code + * @outbuf: output buffer, must have at least 6 bytes of space. + * If %NULL, the length will be computed and returned + * and nothing will be written to @out. + * + * Convert a single character to utf8 + * + * Return value: number of bytes written + **/ + +gint +e_unichar_to_utf8 (gint c, gchar *outbuf) +{ + size_t len = 0; + int first; + int i; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else if (c < 0x10000) + { + first = 0xe0; + len = 3; + } + else if (c < 0x200000) + { + first = 0xf0; + len = 4; + } + else if (c < 0x4000000) + { + first = 0xf8; + len = 5; + } + else + { + first = 0xfc; + len = 6; + } + + if (outbuf) + { + for (i = len - 1; i > 0; --i) + { + outbuf[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + outbuf[0] = c | first; + } + + return len; +} + +gchar * +e_unicode_get_utf8 (const gchar *text, gunichar *out) +{ + *out = g_utf8_get_char (text); + return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text); +} + +/* + * Canonical decomposition + * + * It is copied here from libunicode, because we do not want malloc + * + */ + +typedef struct +{ + unsigned short ch; + char *expansion; +} e_decomposition; + +static e_decomposition e_decomp_table[] = +{ + { 0x00c0, "\x00\x41\x03\x00\0" }, + { 0x00c1, "\x00\x41\x03\x01\0" }, + { 0x00c2, "\x00\x41\x03\x02\0" }, + { 0x00c3, "\x00\x41\x03\x03\0" }, + { 0x00c4, "\x00\x41\x03\x08\0" }, + { 0x00c5, "\x00\x41\x03\x0a\0" }, + { 0x00c7, "\x00\x43\x03\x27\0" }, + { 0x00c8, "\x00\x45\x03\x00\0" }, + { 0x00c9, "\x00\x45\x03\x01\0" }, + { 0x00ca, "\x00\x45\x03\x02\0" }, + { 0x00cb, "\x00\x45\x03\x08\0" }, + { 0x00cc, "\x00\x49\x03\x00\0" }, + { 0x00cd, "\x00\x49\x03\x01\0" }, + { 0x00ce, "\x00\x49\x03\x02\0" }, + { 0x00cf, "\x00\x49\x03\x08\0" }, + { 0x00d1, "\x00\x4e\x03\x03\0" }, + { 0x00d2, "\x00\x4f\x03\x00\0" }, + { 0x00d3, "\x00\x4f\x03\x01\0" }, + { 0x00d4, "\x00\x4f\x03\x02\0" }, + { 0x00d5, "\x00\x4f\x03\x03\0" }, + { 0x00d6, "\x00\x4f\x03\x08\0" }, + { 0x00d9, "\x00\x55\x03\x00\0" }, + { 0x00da, "\x00\x55\x03\x01\0" }, + { 0x00db, "\x00\x55\x03\x02\0" }, + { 0x00dc, "\x00\x55\x03\x08\0" }, + { 0x00dd, "\x00\x59\x03\x01\0" }, + { 0x00e0, "\x00\x61\x03\x00\0" }, + { 0x00e1, "\x00\x61\x03\x01\0" }, + { 0x00e2, "\x00\x61\x03\x02\0" }, + { 0x00e3, "\x00\x61\x03\x03\0" }, + { 0x00e4, "\x00\x61\x03\x08\0" }, + { 0x00e5, "\x00\x61\x03\x0a\0" }, + { 0x00e7, "\x00\x63\x03\x27\0" }, + { 0x00e8, "\x00\x65\x03\x00\0" }, + { 0x00e9, "\x00\x65\x03\x01\0" }, + { 0x00ea, "\x00\x65\x03\x02\0" }, + { 0x00eb, "\x00\x65\x03\x08\0" }, + { 0x00ec, "\x00\x69\x03\x00\0" }, + { 0x00ed, "\x00\x69\x03\x01\0" }, + { 0x00ee, "\x00\x69\x03\x02\0" }, + { 0x00ef, "\x00\x69\x03\x08\0" }, + { 0x00f1, "\x00\x6e\x03\x03\0" }, + { 0x00f2, "\x00\x6f\x03\x00\0" }, + { 0x00f3, "\x00\x6f\x03\x01\0" }, + { 0x00f4, "\x00\x6f\x03\x02\0" }, + { 0x00f5, "\x00\x6f\x03\x03\0" }, + { 0x00f6, "\x00\x6f\x03\x08\0" }, + { 0x00f9, "\x00\x75\x03\x00\0" }, + { 0x00fa, "\x00\x75\x03\x01\0" }, + { 0x00fb, "\x00\x75\x03\x02\0" }, + { 0x00fc, "\x00\x75\x03\x08\0" }, + { 0x00fd, "\x00\x79\x03\x01\0" }, + { 0x00ff, "\x00\x79\x03\x08\0" }, + { 0x0100, "\x00\x41\x03\x04\0" }, + { 0x0101, "\x00\x61\x03\x04\0" }, + { 0x0102, "\x00\x41\x03\x06\0" }, + { 0x0103, "\x00\x61\x03\x06\0" }, + { 0x0104, "\x00\x41\x03\x28\0" }, + { 0x0105, "\x00\x61\x03\x28\0" }, + { 0x0106, "\x00\x43\x03\x01\0" }, + { 0x0107, "\x00\x63\x03\x01\0" }, + { 0x0108, "\x00\x43\x03\x02\0" }, + { 0x0109, "\x00\x63\x03\x02\0" }, + { 0x010a, "\x00\x43\x03\x07\0" }, + { 0x010b, "\x00\x63\x03\x07\0" }, + { 0x010c, "\x00\x43\x03\x0c\0" }, + { 0x010d, "\x00\x63\x03\x0c\0" }, + { 0x010e, "\x00\x44\x03\x0c\0" }, + { 0x010f, "\x00\x64\x03\x0c\0" }, + { 0x0112, "\x00\x45\x03\x04\0" }, + { 0x0113, "\x00\x65\x03\x04\0" }, + { 0x0114, "\x00\x45\x03\x06\0" }, + { 0x0115, "\x00\x65\x03\x06\0" }, + { 0x0116, "\x00\x45\x03\x07\0" }, + { 0x0117, "\x00\x65\x03\x07\0" }, + { 0x0118, "\x00\x45\x03\x28\0" }, + { 0x0119, "\x00\x65\x03\x28\0" }, + { 0x011a, "\x00\x45\x03\x0c\0" }, + { 0x011b, "\x00\x65\x03\x0c\0" }, + { 0x011c, "\x00\x47\x03\x02\0" }, + { 0x011d, "\x00\x67\x03\x02\0" }, + { 0x011e, "\x00\x47\x03\x06\0" }, + { 0x011f, "\x00\x67\x03\x06\0" }, + { 0x0120, "\x00\x47\x03\x07\0" }, + { 0x0121, "\x00\x67\x03\x07\0" }, + { 0x0122, "\x00\x47\x03\x27\0" }, + { 0x0123, "\x00\x67\x03\x27\0" }, + { 0x0124, "\x00\x48\x03\x02\0" }, + { 0x0125, "\x00\x68\x03\x02\0" }, + { 0x0128, "\x00\x49\x03\x03\0" }, + { 0x0129, "\x00\x69\x03\x03\0" }, + { 0x012a, "\x00\x49\x03\x04\0" }, + { 0x012b, "\x00\x69\x03\x04\0" }, + { 0x012c, "\x00\x49\x03\x06\0" }, + { 0x012d, "\x00\x69\x03\x06\0" }, + { 0x012e, "\x00\x49\x03\x28\0" }, + { 0x012f, "\x00\x69\x03\x28\0" }, + { 0x0130, "\x00\x49\x03\x07\0" }, + { 0x0134, "\x00\x4a\x03\x02\0" }, + { 0x0135, "\x00\x6a\x03\x02\0" }, + { 0x0136, "\x00\x4b\x03\x27\0" }, + { 0x0137, "\x00\x6b\x03\x27\0" }, + { 0x0139, "\x00\x4c\x03\x01\0" }, + { 0x013a, "\x00\x6c\x03\x01\0" }, + { 0x013b, "\x00\x4c\x03\x27\0" }, + { 0x013c, "\x00\x6c\x03\x27\0" }, + { 0x013d, "\x00\x4c\x03\x0c\0" }, + { 0x013e, "\x00\x6c\x03\x0c\0" }, + { 0x0143, "\x00\x4e\x03\x01\0" }, + { 0x0144, "\x00\x6e\x03\x01\0" }, + { 0x0145, "\x00\x4e\x03\x27\0" }, + { 0x0146, "\x00\x6e\x03\x27\0" }, + { 0x0147, "\x00\x4e\x03\x0c\0" }, + { 0x0148, "\x00\x6e\x03\x0c\0" }, + { 0x014c, "\x00\x4f\x03\x04\0" }, + { 0x014d, "\x00\x6f\x03\x04\0" }, + { 0x014e, "\x00\x4f\x03\x06\0" }, + { 0x014f, "\x00\x6f\x03\x06\0" }, + { 0x0150, "\x00\x4f\x03\x0b\0" }, + { 0x0151, "\x00\x6f\x03\x0b\0" }, + { 0x0154, "\x00\x52\x03\x01\0" }, + { 0x0155, "\x00\x72\x03\x01\0" }, + { 0x0156, "\x00\x52\x03\x27\0" }, + { 0x0157, "\x00\x72\x03\x27\0" }, + { 0x0158, "\x00\x52\x03\x0c\0" }, + { 0x0159, "\x00\x72\x03\x0c\0" }, + { 0x015a, "\x00\x53\x03\x01\0" }, + { 0x015b, "\x00\x73\x03\x01\0" }, + { 0x015c, "\x00\x53\x03\x02\0" }, + { 0x015d, "\x00\x73\x03\x02\0" }, + { 0x015e, "\x00\x53\x03\x27\0" }, + { 0x015f, "\x00\x73\x03\x27\0" }, + { 0x0160, "\x00\x53\x03\x0c\0" }, + { 0x0161, "\x00\x73\x03\x0c\0" }, + { 0x0162, "\x00\x54\x03\x27\0" }, + { 0x0163, "\x00\x74\x03\x27\0" }, + { 0x0164, "\x00\x54\x03\x0c\0" }, + { 0x0165, "\x00\x74\x03\x0c\0" }, + { 0x0168, "\x00\x55\x03\x03\0" }, + { 0x0169, "\x00\x75\x03\x03\0" }, + { 0x016a, "\x00\x55\x03\x04\0" }, + { 0x016b, "\x00\x75\x03\x04\0" }, + { 0x016c, "\x00\x55\x03\x06\0" }, + { 0x016d, "\x00\x75\x03\x06\0" }, + { 0x016e, "\x00\x55\x03\x0a\0" }, + { 0x016f, "\x00\x75\x03\x0a\0" }, + { 0x0170, "\x00\x55\x03\x0b\0" }, + { 0x0171, "\x00\x75\x03\x0b\0" }, + { 0x0172, "\x00\x55\x03\x28\0" }, + { 0x0173, "\x00\x75\x03\x28\0" }, + { 0x0174, "\x00\x57\x03\x02\0" }, + { 0x0175, "\x00\x77\x03\x02\0" }, + { 0x0176, "\x00\x59\x03\x02\0" }, + { 0x0177, "\x00\x79\x03\x02\0" }, + { 0x0178, "\x00\x59\x03\x08\0" }, + { 0x0179, "\x00\x5a\x03\x01\0" }, + { 0x017a, "\x00\x7a\x03\x01\0" }, + { 0x017b, "\x00\x5a\x03\x07\0" }, + { 0x017c, "\x00\x7a\x03\x07\0" }, + { 0x017d, "\x00\x5a\x03\x0c\0" }, + { 0x017e, "\x00\x7a\x03\x0c\0" }, + { 0x01a0, "\x00\x4f\x03\x1b\0" }, + { 0x01a1, "\x00\x6f\x03\x1b\0" }, + { 0x01af, "\x00\x55\x03\x1b\0" }, + { 0x01b0, "\x00\x75\x03\x1b\0" }, + { 0x01cd, "\x00\x41\x03\x0c\0" }, + { 0x01ce, "\x00\x61\x03\x0c\0" }, + { 0x01cf, "\x00\x49\x03\x0c\0" }, + { 0x01d0, "\x00\x69\x03\x0c\0" }, + { 0x01d1, "\x00\x4f\x03\x0c\0" }, + { 0x01d2, "\x00\x6f\x03\x0c\0" }, + { 0x01d3, "\x00\x55\x03\x0c\0" }, + { 0x01d4, "\x00\x75\x03\x0c\0" }, + { 0x01d5, "\x00\x55\x03\x08\x03\x04\0" }, + { 0x01d6, "\x00\x75\x03\x08\x03\x04\0" }, + { 0x01d7, "\x00\x55\x03\x08\x03\x01\0" }, + { 0x01d8, "\x00\x75\x03\x08\x03\x01\0" }, + { 0x01d9, "\x00\x55\x03\x08\x03\x0c\0" }, + { 0x01da, "\x00\x75\x03\x08\x03\x0c\0" }, + { 0x01db, "\x00\x55\x03\x08\x03\x00\0" }, + { 0x01dc, "\x00\x75\x03\x08\x03\x00\0" }, + { 0x01de, "\x00\x41\x03\x08\x03\x04\0" }, + { 0x01df, "\x00\x61\x03\x08\x03\x04\0" }, + { 0x01e0, "\x00\x41\x03\x07\x03\x04\0" }, + { 0x01e1, "\x00\x61\x03\x07\x03\x04\0" }, + { 0x01e2, "\x00\xc6\x03\x04\0" }, + { 0x01e3, "\x00\xe6\x03\x04\0" }, + { 0x01e6, "\x00\x47\x03\x0c\0" }, + { 0x01e7, "\x00\x67\x03\x0c\0" }, + { 0x01e8, "\x00\x4b\x03\x0c\0" }, + { 0x01e9, "\x00\x6b\x03\x0c\0" }, + { 0x01ea, "\x00\x4f\x03\x28\0" }, + { 0x01eb, "\x00\x6f\x03\x28\0" }, + { 0x01ec, "\x00\x4f\x03\x28\x03\x04\0" }, + { 0x01ed, "\x00\x6f\x03\x28\x03\x04\0" }, + { 0x01ee, "\x01\xb7\x03\x0c\0" }, + { 0x01ef, "\x02\x92\x03\x0c\0" }, + { 0x01f0, "\x00\x6a\x03\x0c\0" }, + { 0x01f4, "\x00\x47\x03\x01\0" }, + { 0x01f5, "\x00\x67\x03\x01\0" }, + { 0x01fa, "\x00\x41\x03\x0a\x03\x01\0" }, + { 0x01fb, "\x00\x61\x03\x0a\x03\x01\0" }, + { 0x01fc, "\x00\xc6\x03\x01\0" }, + { 0x01fd, "\x00\xe6\x03\x01\0" }, + { 0x01fe, "\x00\xd8\x03\x01\0" }, + { 0x01ff, "\x00\xf8\x03\x01\0" }, + { 0x0200, "\x00\x41\x03\x0f\0" }, + { 0x0201, "\x00\x61\x03\x0f\0" }, + { 0x0202, "\x00\x41\x03\x11\0" }, + { 0x0203, "\x00\x61\x03\x11\0" }, + { 0x0204, "\x00\x45\x03\x0f\0" }, + { 0x0205, "\x00\x65\x03\x0f\0" }, + { 0x0206, "\x00\x45\x03\x11\0" }, + { 0x0207, "\x00\x65\x03\x11\0" }, + { 0x0208, "\x00\x49\x03\x0f\0" }, + { 0x0209, "\x00\x69\x03\x0f\0" }, + { 0x020a, "\x00\x49\x03\x11\0" }, + { 0x020b, "\x00\x69\x03\x11\0" }, + { 0x020c, "\x00\x4f\x03\x0f\0" }, + { 0x020d, "\x00\x6f\x03\x0f\0" }, + { 0x020e, "\x00\x4f\x03\x11\0" }, + { 0x020f, "\x00\x6f\x03\x11\0" }, + { 0x0210, "\x00\x52\x03\x0f\0" }, + { 0x0211, "\x00\x72\x03\x0f\0" }, + { 0x0212, "\x00\x52\x03\x11\0" }, + { 0x0213, "\x00\x72\x03\x11\0" }, + { 0x0214, "\x00\x55\x03\x0f\0" }, + { 0x0215, "\x00\x75\x03\x0f\0" }, + { 0x0216, "\x00\x55\x03\x11\0" }, + { 0x0217, "\x00\x75\x03\x11\0" }, + { 0x0340, "\x03\x00\0" }, + { 0x0341, "\x03\x01\0" }, + { 0x0343, "\x03\x13\0" }, + { 0x0344, "\x03\x08\x03\x01\0" }, + { 0x0374, "\x02\xb9\0" }, + { 0x037e, "\x00\x3b\0" }, + { 0x0385, "\x00\xa8\x03\x01\0" }, + { 0x0386, "\x03\x91\x03\x01\0" }, + { 0x0387, "\x00\xb7\0" }, + { 0x0388, "\x03\x95\x03\x01\0" }, + { 0x0389, "\x03\x97\x03\x01\0" }, + { 0x038a, "\x03\x99\x03\x01\0" }, + { 0x038c, "\x03\x9f\x03\x01\0" }, + { 0x038e, "\x03\xa5\x03\x01\0" }, + { 0x038f, "\x03\xa9\x03\x01\0" }, + { 0x0390, "\x03\xb9\x03\x08\x03\x01\0" }, + { 0x03aa, "\x03\x99\x03\x08\0" }, + { 0x03ab, "\x03\xa5\x03\x08\0" }, + { 0x03ac, "\x03\xb1\x03\x01\0" }, + { 0x03ad, "\x03\xb5\x03\x01\0" }, + { 0x03ae, "\x03\xb7\x03\x01\0" }, + { 0x03af, "\x03\xb9\x03\x01\0" }, + { 0x03b0, "\x03\xc5\x03\x08\x03\x01\0" }, + { 0x03ca, "\x03\xb9\x03\x08\0" }, + { 0x03cb, "\x03\xc5\x03\x08\0" }, + { 0x03cc, "\x03\xbf\x03\x01\0" }, + { 0x03cd, "\x03\xc5\x03\x01\0" }, + { 0x03ce, "\x03\xc9\x03\x01\0" }, + { 0x03d3, "\x03\xd2\x03\x01\0" }, + { 0x03d4, "\x03\xd2\x03\x08\0" }, + { 0x0401, "\x04\x15\x03\x08\0" }, + { 0x0403, "\x04\x13\x03\x01\0" }, + { 0x0407, "\x04\x06\x03\x08\0" }, + { 0x040c, "\x04\x1a\x03\x01\0" }, + { 0x040e, "\x04\x23\x03\x06\0" }, + { 0x0419, "\x04\x18\x03\x06\0" }, + { 0x0439, "\x04\x38\x03\x06\0" }, + { 0x0451, "\x04\x35\x03\x08\0" }, + { 0x0453, "\x04\x33\x03\x01\0" }, + { 0x0457, "\x04\x56\x03\x08\0" }, + { 0x045c, "\x04\x3a\x03\x01\0" }, + { 0x045e, "\x04\x43\x03\x06\0" }, + { 0x0476, "\x04\x74\x03\x0f\0" }, + { 0x0477, "\x04\x75\x03\x0f\0" }, + { 0x04c1, "\x04\x16\x03\x06\0" }, + { 0x04c2, "\x04\x36\x03\x06\0" }, + { 0x04d0, "\x04\x10\x03\x06\0" }, + { 0x04d1, "\x04\x30\x03\x06\0" }, + { 0x04d2, "\x04\x10\x03\x08\0" }, + { 0x04d3, "\x04\x30\x03\x08\0" }, + { 0x04d6, "\x04\x15\x03\x06\0" }, + { 0x04d7, "\x04\x35\x03\x06\0" }, + { 0x04da, "\x04\xd8\x03\x08\0" }, + { 0x04db, "\x04\xd9\x03\x08\0" }, + { 0x04dc, "\x04\x16\x03\x08\0" }, + { 0x04dd, "\x04\x36\x03\x08\0" }, + { 0x04de, "\x04\x17\x03\x08\0" }, + { 0x04df, "\x04\x37\x03\x08\0" }, + { 0x04e2, "\x04\x18\x03\x04\0" }, + { 0x04e3, "\x04\x38\x03\x04\0" }, + { 0x04e4, "\x04\x18\x03\x08\0" }, + { 0x04e5, "\x04\x38\x03\x08\0" }, + { 0x04e6, "\x04\x1e\x03\x08\0" }, + { 0x04e7, "\x04\x3e\x03\x08\0" }, + { 0x04ea, "\x04\xe8\x03\x08\0" }, + { 0x04eb, "\x04\xe9\x03\x08\0" }, + { 0x04ee, "\x04\x23\x03\x04\0" }, + { 0x04ef, "\x04\x43\x03\x04\0" }, + { 0x04f0, "\x04\x23\x03\x08\0" }, + { 0x04f1, "\x04\x43\x03\x08\0" }, + { 0x04f2, "\x04\x23\x03\x0b\0" }, + { 0x04f3, "\x04\x43\x03\x0b\0" }, + { 0x04f4, "\x04\x27\x03\x08\0" }, + { 0x04f5, "\x04\x47\x03\x08\0" }, + { 0x04f8, "\x04\x2b\x03\x08\0" }, + { 0x04f9, "\x04\x4b\x03\x08\0" }, + { 0x0929, "\x09\x28\x09\x3c\0" }, + { 0x0931, "\x09\x30\x09\x3c\0" }, + { 0x0934, "\x09\x33\x09\x3c\0" }, + { 0x0958, "\x09\x15\x09\x3c\0" }, + { 0x0959, "\x09\x16\x09\x3c\0" }, + { 0x095a, "\x09\x17\x09\x3c\0" }, + { 0x095b, "\x09\x1c\x09\x3c\0" }, + { 0x095c, "\x09\x21\x09\x3c\0" }, + { 0x095d, "\x09\x22\x09\x3c\0" }, + { 0x095e, "\x09\x2b\x09\x3c\0" }, + { 0x095f, "\x09\x2f\x09\x3c\0" }, + { 0x09b0, "\x09\xac\x09\xbc\0" }, + { 0x09cb, "\x09\xc7\x09\xbe\0" }, + { 0x09cc, "\x09\xc7\x09\xd7\0" }, + { 0x09dc, "\x09\xa1\x09\xbc\0" }, + { 0x09dd, "\x09\xa2\x09\xbc\0" }, + { 0x09df, "\x09\xaf\x09\xbc\0" }, + { 0x0a59, "\x0a\x16\x0a\x3c\0" }, + { 0x0a5a, "\x0a\x17\x0a\x3c\0" }, + { 0x0a5b, "\x0a\x1c\x0a\x3c\0" }, + { 0x0a5c, "\x0a\x21\x0a\x3c\0" }, + { 0x0a5e, "\x0a\x2b\x0a\x3c\0" }, + { 0x0b48, "\x0b\x47\x0b\x56\0" }, + { 0x0b4b, "\x0b\x47\x0b\x3e\0" }, + { 0x0b4c, "\x0b\x47\x0b\x57\0" }, + { 0x0b5c, "\x0b\x21\x0b\x3c\0" }, + { 0x0b5d, "\x0b\x22\x0b\x3c\0" }, + { 0x0b5f, "\x0b\x2f\x0b\x3c\0" }, + { 0x0b94, "\x0b\x92\x0b\xd7\0" }, + { 0x0bca, "\x0b\xc6\x0b\xbe\0" }, + { 0x0bcb, "\x0b\xc7\x0b\xbe\0" }, + { 0x0bcc, "\x0b\xc6\x0b\xd7\0" }, + { 0x0c48, "\x0c\x46\x0c\x56\0" }, + { 0x0cc0, "\x0c\xbf\x0c\xd5\0" }, + { 0x0cc7, "\x0c\xc6\x0c\xd5\0" }, + { 0x0cc8, "\x0c\xc6\x0c\xd6\0" }, + { 0x0cca, "\x0c\xc6\x0c\xc2\0" }, + { 0x0ccb, "\x0c\xc6\x0c\xc2\x0c\xd5\0" }, + { 0x0d4a, "\x0d\x46\x0d\x3e\0" }, + { 0x0d4b, "\x0d\x47\x0d\x3e\0" }, + { 0x0d4c, "\x0d\x46\x0d\x57\0" }, + { 0x0e33, "\x0e\x4d\x0e\x32\0" }, + { 0x0eb3, "\x0e\xcd\x0e\xb2\0" }, + { 0x0f43, "\x0f\x42\x0f\xb7\0" }, + { 0x0f4d, "\x0f\x4c\x0f\xb7\0" }, + { 0x0f52, "\x0f\x51\x0f\xb7\0" }, + { 0x0f57, "\x0f\x56\x0f\xb7\0" }, + { 0x0f5c, "\x0f\x5b\x0f\xb7\0" }, + { 0x0f69, "\x0f\x40\x0f\xb5\0" }, + { 0x0f73, "\x0f\x71\x0f\x72\0" }, + { 0x0f75, "\x0f\x71\x0f\x74\0" }, + { 0x0f76, "\x0f\xb2\x0f\x80\0" }, + { 0x0f78, "\x0f\xb3\x0f\x80\0" }, + { 0x0f81, "\x0f\x71\x0f\x80\0" }, + { 0x0f93, "\x0f\x92\x0f\xb7\0" }, + { 0x0f9d, "\x0f\x9c\x0f\xb7\0" }, + { 0x0fa2, "\x0f\xa1\x0f\xb7\0" }, + { 0x0fa7, "\x0f\xa6\x0f\xb7\0" }, + { 0x0fac, "\x0f\xab\x0f\xb7\0" }, + { 0x0fb9, "\x0f\x90\x0f\xb5\0" }, + { 0x1e00, "\x00\x41\x03\x25\0" }, + { 0x1e01, "\x00\x61\x03\x25\0" }, + { 0x1e02, "\x00\x42\x03\x07\0" }, + { 0x1e03, "\x00\x62\x03\x07\0" }, + { 0x1e04, "\x00\x42\x03\x23\0" }, + { 0x1e05, "\x00\x62\x03\x23\0" }, + { 0x1e06, "\x00\x42\x03\x31\0" }, + { 0x1e07, "\x00\x62\x03\x31\0" }, + { 0x1e08, "\x00\x43\x03\x27\x03\x01\0" }, + { 0x1e09, "\x00\x63\x03\x27\x03\x01\0" }, + { 0x1e0a, "\x00\x44\x03\x07\0" }, + { 0x1e0b, "\x00\x64\x03\x07\0" }, + { 0x1e0c, "\x00\x44\x03\x23\0" }, + { 0x1e0d, "\x00\x64\x03\x23\0" }, + { 0x1e0e, "\x00\x44\x03\x31\0" }, + { 0x1e0f, "\x00\x64\x03\x31\0" }, + { 0x1e10, "\x00\x44\x03\x27\0" }, + { 0x1e11, "\x00\x64\x03\x27\0" }, + { 0x1e12, "\x00\x44\x03\x2d\0" }, + { 0x1e13, "\x00\x64\x03\x2d\0" }, + { 0x1e14, "\x00\x45\x03\x04\x03\x00\0" }, + { 0x1e15, "\x00\x65\x03\x04\x03\x00\0" }, + { 0x1e16, "\x00\x45\x03\x04\x03\x01\0" }, + { 0x1e17, "\x00\x65\x03\x04\x03\x01\0" }, + { 0x1e18, "\x00\x45\x03\x2d\0" }, + { 0x1e19, "\x00\x65\x03\x2d\0" }, + { 0x1e1a, "\x00\x45\x03\x30\0" }, + { 0x1e1b, "\x00\x65\x03\x30\0" }, + { 0x1e1c, "\x00\x45\x03\x27\x03\x06\0" }, + { 0x1e1d, "\x00\x65\x03\x27\x03\x06\0" }, + { 0x1e1e, "\x00\x46\x03\x07\0" }, + { 0x1e1f, "\x00\x66\x03\x07\0" }, + { 0x1e20, "\x00\x47\x03\x04\0" }, + { 0x1e21, "\x00\x67\x03\x04\0" }, + { 0x1e22, "\x00\x48\x03\x07\0" }, + { 0x1e23, "\x00\x68\x03\x07\0" }, + { 0x1e24, "\x00\x48\x03\x23\0" }, + { 0x1e25, "\x00\x68\x03\x23\0" }, + { 0x1e26, "\x00\x48\x03\x08\0" }, + { 0x1e27, "\x00\x68\x03\x08\0" }, + { 0x1e28, "\x00\x48\x03\x27\0" }, + { 0x1e29, "\x00\x68\x03\x27\0" }, + { 0x1e2a, "\x00\x48\x03\x2e\0" }, + { 0x1e2b, "\x00\x68\x03\x2e\0" }, + { 0x1e2c, "\x00\x49\x03\x30\0" }, + { 0x1e2d, "\x00\x69\x03\x30\0" }, + { 0x1e2e, "\x00\x49\x03\x08\x03\x01\0" }, + { 0x1e2f, "\x00\x69\x03\x08\x03\x01\0" }, + { 0x1e30, "\x00\x4b\x03\x01\0" }, + { 0x1e31, "\x00\x6b\x03\x01\0" }, + { 0x1e32, "\x00\x4b\x03\x23\0" }, + { 0x1e33, "\x00\x6b\x03\x23\0" }, + { 0x1e34, "\x00\x4b\x03\x31\0" }, + { 0x1e35, "\x00\x6b\x03\x31\0" }, + { 0x1e36, "\x00\x4c\x03\x23\0" }, + { 0x1e37, "\x00\x6c\x03\x23\0" }, + { 0x1e38, "\x00\x4c\x03\x23\x03\x04\0" }, + { 0x1e39, "\x00\x6c\x03\x23\x03\x04\0" }, + { 0x1e3a, "\x00\x4c\x03\x31\0" }, + { 0x1e3b, "\x00\x6c\x03\x31\0" }, + { 0x1e3c, "\x00\x4c\x03\x2d\0" }, + { 0x1e3d, "\x00\x6c\x03\x2d\0" }, + { 0x1e3e, "\x00\x4d\x03\x01\0" }, + { 0x1e3f, "\x00\x6d\x03\x01\0" }, + { 0x1e40, "\x00\x4d\x03\x07\0" }, + { 0x1e41, "\x00\x6d\x03\x07\0" }, + { 0x1e42, "\x00\x4d\x03\x23\0" }, + { 0x1e43, "\x00\x6d\x03\x23\0" }, + { 0x1e44, "\x00\x4e\x03\x07\0" }, + { 0x1e45, "\x00\x6e\x03\x07\0" }, + { 0x1e46, "\x00\x4e\x03\x23\0" }, + { 0x1e47, "\x00\x6e\x03\x23\0" }, + { 0x1e48, "\x00\x4e\x03\x31\0" }, + { 0x1e49, "\x00\x6e\x03\x31\0" }, + { 0x1e4a, "\x00\x4e\x03\x2d\0" }, + { 0x1e4b, "\x00\x6e\x03\x2d\0" }, + { 0x1e4c, "\x00\x4f\x03\x03\x03\x01\0" }, + { 0x1e4d, "\x00\x6f\x03\x03\x03\x01\0" }, + { 0x1e4e, "\x00\x4f\x03\x03\x03\x08\0" }, + { 0x1e4f, "\x00\x6f\x03\x03\x03\x08\0" }, + { 0x1e50, "\x00\x4f\x03\x04\x03\x00\0" }, + { 0x1e51, "\x00\x6f\x03\x04\x03\x00\0" }, + { 0x1e52, "\x00\x4f\x03\x04\x03\x01\0" }, + { 0x1e53, "\x00\x6f\x03\x04\x03\x01\0" }, + { 0x1e54, "\x00\x50\x03\x01\0" }, + { 0x1e55, "\x00\x70\x03\x01\0" }, + { 0x1e56, "\x00\x50\x03\x07\0" }, + { 0x1e57, "\x00\x70\x03\x07\0" }, + { 0x1e58, "\x00\x52\x03\x07\0" }, + { 0x1e59, "\x00\x72\x03\x07\0" }, + { 0x1e5a, "\x00\x52\x03\x23\0" }, + { 0x1e5b, "\x00\x72\x03\x23\0" }, + { 0x1e5c, "\x00\x52\x03\x23\x03\x04\0" }, + { 0x1e5d, "\x00\x72\x03\x23\x03\x04\0" }, + { 0x1e5e, "\x00\x52\x03\x31\0" }, + { 0x1e5f, "\x00\x72\x03\x31\0" }, + { 0x1e60, "\x00\x53\x03\x07\0" }, + { 0x1e61, "\x00\x73\x03\x07\0" }, + { 0x1e62, "\x00\x53\x03\x23\0" }, + { 0x1e63, "\x00\x73\x03\x23\0" }, + { 0x1e64, "\x00\x53\x03\x01\x03\x07\0" }, + { 0x1e65, "\x00\x73\x03\x01\x03\x07\0" }, + { 0x1e66, "\x00\x53\x03\x0c\x03\x07\0" }, + { 0x1e67, "\x00\x73\x03\x0c\x03\x07\0" }, + { 0x1e68, "\x00\x53\x03\x23\x03\x07\0" }, + { 0x1e69, "\x00\x73\x03\x23\x03\x07\0" }, + { 0x1e6a, "\x00\x54\x03\x07\0" }, + { 0x1e6b, "\x00\x74\x03\x07\0" }, + { 0x1e6c, "\x00\x54\x03\x23\0" }, + { 0x1e6d, "\x00\x74\x03\x23\0" }, + { 0x1e6e, "\x00\x54\x03\x31\0" }, + { 0x1e6f, "\x00\x74\x03\x31\0" }, + { 0x1e70, "\x00\x54\x03\x2d\0" }, + { 0x1e71, "\x00\x74\x03\x2d\0" }, + { 0x1e72, "\x00\x55\x03\x24\0" }, + { 0x1e73, "\x00\x75\x03\x24\0" }, + { 0x1e74, "\x00\x55\x03\x30\0" }, + { 0x1e75, "\x00\x75\x03\x30\0" }, + { 0x1e76, "\x00\x55\x03\x2d\0" }, + { 0x1e77, "\x00\x75\x03\x2d\0" }, + { 0x1e78, "\x00\x55\x03\x03\x03\x01\0" }, + { 0x1e79, "\x00\x75\x03\x03\x03\x01\0" }, + { 0x1e7a, "\x00\x55\x03\x04\x03\x08\0" }, + { 0x1e7b, "\x00\x75\x03\x04\x03\x08\0" }, + { 0x1e7c, "\x00\x56\x03\x03\0" }, + { 0x1e7d, "\x00\x76\x03\x03\0" }, + { 0x1e7e, "\x00\x56\x03\x23\0" }, + { 0x1e7f, "\x00\x76\x03\x23\0" }, + { 0x1e80, "\x00\x57\x03\x00\0" }, + { 0x1e81, "\x00\x77\x03\x00\0" }, + { 0x1e82, "\x00\x57\x03\x01\0" }, + { 0x1e83, "\x00\x77\x03\x01\0" }, + { 0x1e84, "\x00\x57\x03\x08\0" }, + { 0x1e85, "\x00\x77\x03\x08\0" }, + { 0x1e86, "\x00\x57\x03\x07\0" }, + { 0x1e87, "\x00\x77\x03\x07\0" }, + { 0x1e88, "\x00\x57\x03\x23\0" }, + { 0x1e89, "\x00\x77\x03\x23\0" }, + { 0x1e8a, "\x00\x58\x03\x07\0" }, + { 0x1e8b, "\x00\x78\x03\x07\0" }, + { 0x1e8c, "\x00\x58\x03\x08\0" }, + { 0x1e8d, "\x00\x78\x03\x08\0" }, + { 0x1e8e, "\x00\x59\x03\x07\0" }, + { 0x1e8f, "\x00\x79\x03\x07\0" }, + { 0x1e90, "\x00\x5a\x03\x02\0" }, + { 0x1e91, "\x00\x7a\x03\x02\0" }, + { 0x1e92, "\x00\x5a\x03\x23\0" }, + { 0x1e93, "\x00\x7a\x03\x23\0" }, + { 0x1e94, "\x00\x5a\x03\x31\0" }, + { 0x1e95, "\x00\x7a\x03\x31\0" }, + { 0x1e96, "\x00\x68\x03\x31\0" }, + { 0x1e97, "\x00\x74\x03\x08\0" }, + { 0x1e98, "\x00\x77\x03\x0a\0" }, + { 0x1e99, "\x00\x79\x03\x0a\0" }, + { 0x1e9b, "\x01\x7f\x03\x07\0" }, + { 0x1ea0, "\x00\x41\x03\x23\0" }, + { 0x1ea1, "\x00\x61\x03\x23\0" }, + { 0x1ea2, "\x00\x41\x03\x09\0" }, + { 0x1ea3, "\x00\x61\x03\x09\0" }, + { 0x1ea4, "\x00\x41\x03\x02\x03\x01\0" }, + { 0x1ea5, "\x00\x61\x03\x02\x03\x01\0" }, + { 0x1ea6, "\x00\x41\x03\x02\x03\x00\0" }, + { 0x1ea7, "\x00\x61\x03\x02\x03\x00\0" }, + { 0x1ea8, "\x00\x41\x03\x02\x03\x09\0" }, + { 0x1ea9, "\x00\x61\x03\x02\x03\x09\0" }, + { 0x1eaa, "\x00\x41\x03\x02\x03\x03\0" }, + { 0x1eab, "\x00\x61\x03\x02\x03\x03\0" }, + { 0x1eac, "\x00\x41\x03\x23\x03\x02\0" }, + { 0x1ead, "\x00\x61\x03\x23\x03\x02\0" }, + { 0x1eae, "\x00\x41\x03\x06\x03\x01\0" }, + { 0x1eaf, "\x00\x61\x03\x06\x03\x01\0" }, + { 0x1eb0, "\x00\x41\x03\x06\x03\x00\0" }, + { 0x1eb1, "\x00\x61\x03\x06\x03\x00\0" }, + { 0x1eb2, "\x00\x41\x03\x06\x03\x09\0" }, + { 0x1eb3, "\x00\x61\x03\x06\x03\x09\0" }, + { 0x1eb4, "\x00\x41\x03\x06\x03\x03\0" }, + { 0x1eb5, "\x00\x61\x03\x06\x03\x03\0" }, + { 0x1eb6, "\x00\x41\x03\x23\x03\x06\0" }, + { 0x1eb7, "\x00\x61\x03\x23\x03\x06\0" }, + { 0x1eb8, "\x00\x45\x03\x23\0" }, + { 0x1eb9, "\x00\x65\x03\x23\0" }, + { 0x1eba, "\x00\x45\x03\x09\0" }, + { 0x1ebb, "\x00\x65\x03\x09\0" }, + { 0x1ebc, "\x00\x45\x03\x03\0" }, + { 0x1ebd, "\x00\x65\x03\x03\0" }, + { 0x1ebe, "\x00\x45\x03\x02\x03\x01\0" }, + { 0x1ebf, "\x00\x65\x03\x02\x03\x01\0" }, + { 0x1ec0, "\x00\x45\x03\x02\x03\x00\0" }, + { 0x1ec1, "\x00\x65\x03\x02\x03\x00\0" }, + { 0x1ec2, "\x00\x45\x03\x02\x03\x09\0" }, + { 0x1ec3, "\x00\x65\x03\x02\x03\x09\0" }, + { 0x1ec4, "\x00\x45\x03\x02\x03\x03\0" }, + { 0x1ec5, "\x00\x65\x03\x02\x03\x03\0" }, + { 0x1ec6, "\x00\x45\x03\x23\x03\x02\0" }, + { 0x1ec7, "\x00\x65\x03\x23\x03\x02\0" }, + { 0x1ec8, "\x00\x49\x03\x09\0" }, + { 0x1ec9, "\x00\x69\x03\x09\0" }, + { 0x1eca, "\x00\x49\x03\x23\0" }, + { 0x1ecb, "\x00\x69\x03\x23\0" }, + { 0x1ecc, "\x00\x4f\x03\x23\0" }, + { 0x1ecd, "\x00\x6f\x03\x23\0" }, + { 0x1ece, "\x00\x4f\x03\x09\0" }, + { 0x1ecf, "\x00\x6f\x03\x09\0" }, + { 0x1ed0, "\x00\x4f\x03\x02\x03\x01\0" }, + { 0x1ed1, "\x00\x6f\x03\x02\x03\x01\0" }, + { 0x1ed2, "\x00\x4f\x03\x02\x03\x00\0" }, + { 0x1ed3, "\x00\x6f\x03\x02\x03\x00\0" }, + { 0x1ed4, "\x00\x4f\x03\x02\x03\x09\0" }, + { 0x1ed5, "\x00\x6f\x03\x02\x03\x09\0" }, + { 0x1ed6, "\x00\x4f\x03\x02\x03\x03\0" }, + { 0x1ed7, "\x00\x6f\x03\x02\x03\x03\0" }, + { 0x1ed8, "\x00\x4f\x03\x23\x03\x02\0" }, + { 0x1ed9, "\x00\x6f\x03\x23\x03\x02\0" }, + { 0x1eda, "\x00\x4f\x03\x1b\x03\x01\0" }, + { 0x1edb, "\x00\x6f\x03\x1b\x03\x01\0" }, + { 0x1edc, "\x00\x4f\x03\x1b\x03\x00\0" }, + { 0x1edd, "\x00\x6f\x03\x1b\x03\x00\0" }, + { 0x1ede, "\x00\x4f\x03\x1b\x03\x09\0" }, + { 0x1edf, "\x00\x6f\x03\x1b\x03\x09\0" }, + { 0x1ee0, "\x00\x4f\x03\x1b\x03\x03\0" }, + { 0x1ee1, "\x00\x6f\x03\x1b\x03\x03\0" }, + { 0x1ee2, "\x00\x4f\x03\x1b\x03\x23\0" }, + { 0x1ee3, "\x00\x6f\x03\x1b\x03\x23\0" }, + { 0x1ee4, "\x00\x55\x03\x23\0" }, + { 0x1ee5, "\x00\x75\x03\x23\0" }, + { 0x1ee6, "\x00\x55\x03\x09\0" }, + { 0x1ee7, "\x00\x75\x03\x09\0" }, + { 0x1ee8, "\x00\x55\x03\x1b\x03\x01\0" }, + { 0x1ee9, "\x00\x75\x03\x1b\x03\x01\0" }, + { 0x1eea, "\x00\x55\x03\x1b\x03\x00\0" }, + { 0x1eeb, "\x00\x75\x03\x1b\x03\x00\0" }, + { 0x1eec, "\x00\x55\x03\x1b\x03\x09\0" }, + { 0x1eed, "\x00\x75\x03\x1b\x03\x09\0" }, + { 0x1eee, "\x00\x55\x03\x1b\x03\x03\0" }, + { 0x1eef, "\x00\x75\x03\x1b\x03\x03\0" }, + { 0x1ef0, "\x00\x55\x03\x1b\x03\x23\0" }, + { 0x1ef1, "\x00\x75\x03\x1b\x03\x23\0" }, + { 0x1ef2, "\x00\x59\x03\x00\0" }, + { 0x1ef3, "\x00\x79\x03\x00\0" }, + { 0x1ef4, "\x00\x59\x03\x23\0" }, + { 0x1ef5, "\x00\x79\x03\x23\0" }, + { 0x1ef6, "\x00\x59\x03\x09\0" }, + { 0x1ef7, "\x00\x79\x03\x09\0" }, + { 0x1ef8, "\x00\x59\x03\x03\0" }, + { 0x1ef9, "\x00\x79\x03\x03\0" }, + { 0x1f00, "\x03\xb1\x03\x13\0" }, + { 0x1f01, "\x03\xb1\x03\x14\0" }, + { 0x1f02, "\x03\xb1\x03\x13\x03\x00\0" }, + { 0x1f03, "\x03\xb1\x03\x14\x03\x00\0" }, + { 0x1f04, "\x03\xb1\x03\x13\x03\x01\0" }, + { 0x1f05, "\x03\xb1\x03\x14\x03\x01\0" }, + { 0x1f06, "\x03\xb1\x03\x13\x03\x42\0" }, + { 0x1f07, "\x03\xb1\x03\x14\x03\x42\0" }, + { 0x1f08, "\x03\x91\x03\x13\0" }, + { 0x1f09, "\x03\x91\x03\x14\0" }, + { 0x1f0a, "\x03\x91\x03\x13\x03\x00\0" }, + { 0x1f0b, "\x03\x91\x03\x14\x03\x00\0" }, + { 0x1f0c, "\x03\x91\x03\x13\x03\x01\0" }, + { 0x1f0d, "\x03\x91\x03\x14\x03\x01\0" }, + { 0x1f0e, "\x03\x91\x03\x13\x03\x42\0" }, + { 0x1f0f, "\x03\x91\x03\x14\x03\x42\0" }, + { 0x1f10, "\x03\xb5\x03\x13\0" }, + { 0x1f11, "\x03\xb5\x03\x14\0" }, + { 0x1f12, "\x03\xb5\x03\x13\x03\x00\0" }, + { 0x1f13, "\x03\xb5\x03\x14\x03\x00\0" }, + { 0x1f14, "\x03\xb5\x03\x13\x03\x01\0" }, + { 0x1f15, "\x03\xb5\x03\x14\x03\x01\0" }, + { 0x1f18, "\x03\x95\x03\x13\0" }, + { 0x1f19, "\x03\x95\x03\x14\0" }, + { 0x1f1a, "\x03\x95\x03\x13\x03\x00\0" }, + { 0x1f1b, "\x03\x95\x03\x14\x03\x00\0" }, + { 0x1f1c, "\x03\x95\x03\x13\x03\x01\0" }, + { 0x1f1d, "\x03\x95\x03\x14\x03\x01\0" }, + { 0x1f20, "\x03\xb7\x03\x13\0" }, + { 0x1f21, "\x03\xb7\x03\x14\0" }, + { 0x1f22, "\x03\xb7\x03\x13\x03\x00\0" }, + { 0x1f23, "\x03\xb7\x03\x14\x03\x00\0" }, + { 0x1f24, "\x03\xb7\x03\x13\x03\x01\0" }, + { 0x1f25, "\x03\xb7\x03\x14\x03\x01\0" }, + { 0x1f26, "\x03\xb7\x03\x13\x03\x42\0" }, + { 0x1f27, "\x03\xb7\x03\x14\x03\x42\0" }, + { 0x1f28, "\x03\x97\x03\x13\0" }, + { 0x1f29, "\x03\x97\x03\x14\0" }, + { 0x1f2a, "\x03\x97\x03\x13\x03\x00\0" }, + { 0x1f2b, "\x03\x97\x03\x14\x03\x00\0" }, + { 0x1f2c, "\x03\x97\x03\x13\x03\x01\0" }, + { 0x1f2d, "\x03\x97\x03\x14\x03\x01\0" }, + { 0x1f2e, "\x03\x97\x03\x13\x03\x42\0" }, + { 0x1f2f, "\x03\x97\x03\x14\x03\x42\0" }, + { 0x1f30, "\x03\xb9\x03\x13\0" }, + { 0x1f31, "\x03\xb9\x03\x14\0" }, + { 0x1f32, "\x03\xb9\x03\x13\x03\x00\0" }, + { 0x1f33, "\x03\xb9\x03\x14\x03\x00\0" }, + { 0x1f34, "\x03\xb9\x03\x13\x03\x01\0" }, + { 0x1f35, "\x03\xb9\x03\x14\x03\x01\0" }, + { 0x1f36, "\x03\xb9\x03\x13\x03\x42\0" }, + { 0x1f37, "\x03\xb9\x03\x14\x03\x42\0" }, + { 0x1f38, "\x03\x99\x03\x13\0" }, + { 0x1f39, "\x03\x99\x03\x14\0" }, + { 0x1f3a, "\x03\x99\x03\x13\x03\x00\0" }, + { 0x1f3b, "\x03\x99\x03\x14\x03\x00\0" }, + { 0x1f3c, "\x03\x99\x03\x13\x03\x01\0" }, + { 0x1f3d, "\x03\x99\x03\x14\x03\x01\0" }, + { 0x1f3e, "\x03\x99\x03\x13\x03\x42\0" }, + { 0x1f3f, "\x03\x99\x03\x14\x03\x42\0" }, + { 0x1f40, "\x03\xbf\x03\x13\0" }, + { 0x1f41, "\x03\xbf\x03\x14\0" }, + { 0x1f42, "\x03\xbf\x03\x13\x03\x00\0" }, + { 0x1f43, "\x03\xbf\x03\x14\x03\x00\0" }, + { 0x1f44, "\x03\xbf\x03\x13\x03\x01\0" }, + { 0x1f45, "\x03\xbf\x03\x14\x03\x01\0" }, + { 0x1f48, "\x03\x9f\x03\x13\0" }, + { 0x1f49, "\x03\x9f\x03\x14\0" }, + { 0x1f4a, "\x03\x9f\x03\x13\x03\x00\0" }, + { 0x1f4b, "\x03\x9f\x03\x14\x03\x00\0" }, + { 0x1f4c, "\x03\x9f\x03\x13\x03\x01\0" }, + { 0x1f4d, "\x03\x9f\x03\x14\x03\x01\0" }, + { 0x1f50, "\x03\xc5\x03\x13\0" }, + { 0x1f51, "\x03\xc5\x03\x14\0" }, + { 0x1f52, "\x03\xc5\x03\x13\x03\x00\0" }, + { 0x1f53, "\x03\xc5\x03\x14\x03\x00\0" }, + { 0x1f54, "\x03\xc5\x03\x13\x03\x01\0" }, + { 0x1f55, "\x03\xc5\x03\x14\x03\x01\0" }, + { 0x1f56, "\x03\xc5\x03\x13\x03\x42\0" }, + { 0x1f57, "\x03\xc5\x03\x14\x03\x42\0" }, + { 0x1f59, "\x03\xa5\x03\x14\0" }, + { 0x1f5b, "\x03\xa5\x03\x14\x03\x00\0" }, + { 0x1f5d, "\x03\xa5\x03\x14\x03\x01\0" }, + { 0x1f5f, "\x03\xa5\x03\x14\x03\x42\0" }, + { 0x1f60, "\x03\xc9\x03\x13\0" }, + { 0x1f61, "\x03\xc9\x03\x14\0" }, + { 0x1f62, "\x03\xc9\x03\x13\x03\x00\0" }, + { 0x1f63, "\x03\xc9\x03\x14\x03\x00\0" }, + { 0x1f64, "\x03\xc9\x03\x13\x03\x01\0" }, + { 0x1f65, "\x03\xc9\x03\x14\x03\x01\0" }, + { 0x1f66, "\x03\xc9\x03\x13\x03\x42\0" }, + { 0x1f67, "\x03\xc9\x03\x14\x03\x42\0" }, + { 0x1f68, "\x03\xa9\x03\x13\0" }, + { 0x1f69, "\x03\xa9\x03\x14\0" }, + { 0x1f6a, "\x03\xa9\x03\x13\x03\x00\0" }, + { 0x1f6b, "\x03\xa9\x03\x14\x03\x00\0" }, + { 0x1f6c, "\x03\xa9\x03\x13\x03\x01\0" }, + { 0x1f6d, "\x03\xa9\x03\x14\x03\x01\0" }, + { 0x1f6e, "\x03\xa9\x03\x13\x03\x42\0" }, + { 0x1f6f, "\x03\xa9\x03\x14\x03\x42\0" }, + { 0x1f70, "\x03\xb1\x03\x00\0" }, + { 0x1f71, "\x03\xb1\x03\x01\0" }, + { 0x1f72, "\x03\xb5\x03\x00\0" }, + { 0x1f73, "\x03\xb5\x03\x01\0" }, + { 0x1f74, "\x03\xb7\x03\x00\0" }, + { 0x1f75, "\x03\xb7\x03\x01\0" }, + { 0x1f76, "\x03\xb9\x03\x00\0" }, + { 0x1f77, "\x03\xb9\x03\x01\0" }, + { 0x1f78, "\x03\xbf\x03\x00\0" }, + { 0x1f79, "\x03\xbf\x03\x01\0" }, + { 0x1f7a, "\x03\xc5\x03\x00\0" }, + { 0x1f7b, "\x03\xc5\x03\x01\0" }, + { 0x1f7c, "\x03\xc9\x03\x00\0" }, + { 0x1f7d, "\x03\xc9\x03\x01\0" }, + { 0x1f80, "\x03\xb1\x03\x13\x03\x45\0" }, + { 0x1f81, "\x03\xb1\x03\x14\x03\x45\0" }, + { 0x1f82, "\x03\xb1\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f83, "\x03\xb1\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f84, "\x03\xb1\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f85, "\x03\xb1\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f86, "\x03\xb1\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f87, "\x03\xb1\x03\x14\x03\x42\x03\x45\0" }, + { 0x1f88, "\x03\x91\x03\x13\x03\x45\0" }, + { 0x1f89, "\x03\x91\x03\x14\x03\x45\0" }, + { 0x1f8a, "\x03\x91\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f8b, "\x03\x91\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f8c, "\x03\x91\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f8d, "\x03\x91\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f8e, "\x03\x91\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f8f, "\x03\x91\x03\x14\x03\x42\x03\x45\0" }, + { 0x1f90, "\x03\xb7\x03\x13\x03\x45\0" }, + { 0x1f91, "\x03\xb7\x03\x14\x03\x45\0" }, + { 0x1f92, "\x03\xb7\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f93, "\x03\xb7\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f94, "\x03\xb7\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f95, "\x03\xb7\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f96, "\x03\xb7\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f97, "\x03\xb7\x03\x14\x03\x42\x03\x45\0" }, + { 0x1f98, "\x03\x97\x03\x13\x03\x45\0" }, + { 0x1f99, "\x03\x97\x03\x14\x03\x45\0" }, + { 0x1f9a, "\x03\x97\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f9b, "\x03\x97\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f9c, "\x03\x97\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f9d, "\x03\x97\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f9e, "\x03\x97\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f9f, "\x03\x97\x03\x14\x03\x42\x03\x45\0" }, + { 0x1fa0, "\x03\xc9\x03\x13\x03\x45\0" }, + { 0x1fa1, "\x03\xc9\x03\x14\x03\x45\0" }, + { 0x1fa2, "\x03\xc9\x03\x13\x03\x00\x03\x45\0" }, + { 0x1fa3, "\x03\xc9\x03\x14\x03\x00\x03\x45\0" }, + { 0x1fa4, "\x03\xc9\x03\x13\x03\x01\x03\x45\0" }, + { 0x1fa5, "\x03\xc9\x03\x14\x03\x01\x03\x45\0" }, + { 0x1fa6, "\x03\xc9\x03\x13\x03\x42\x03\x45\0" }, + { 0x1fa7, "\x03\xc9\x03\x14\x03\x42\x03\x45\0" }, + { 0x1fa8, "\x03\xa9\x03\x13\x03\x45\0" }, + { 0x1fa9, "\x03\xa9\x03\x14\x03\x45\0" }, + { 0x1faa, "\x03\xa9\x03\x13\x03\x00\x03\x45\0" }, + { 0x1fab, "\x03\xa9\x03\x14\x03\x00\x03\x45\0" }, + { 0x1fac, "\x03\xa9\x03\x13\x03\x01\x03\x45\0" }, + { 0x1fad, "\x03\xa9\x03\x14\x03\x01\x03\x45\0" }, + { 0x1fae, "\x03\xa9\x03\x13\x03\x42\x03\x45\0" }, + { 0x1faf, "\x03\xa9\x03\x14\x03\x42\x03\x45\0" }, + { 0x1fb0, "\x03\xb1\x03\x06\0" }, + { 0x1fb1, "\x03\xb1\x03\x04\0" }, + { 0x1fb2, "\x03\xb1\x03\x00\x03\x45\0" }, + { 0x1fb3, "\x03\xb1\x03\x45\0" }, + { 0x1fb4, "\x03\xb1\x03\x01\x03\x45\0" }, + { 0x1fb6, "\x03\xb1\x03\x42\0" }, + { 0x1fb7, "\x03\xb1\x03\x42\x03\x45\0" }, + { 0x1fb8, "\x03\x91\x03\x06\0" }, + { 0x1fb9, "\x03\x91\x03\x04\0" }, + { 0x1fba, "\x03\x91\x03\x00\0" }, + { 0x1fbb, "\x03\x91\x03\x01\0" }, + { 0x1fbc, "\x03\x91\x03\x45\0" }, + { 0x1fbe, "\x03\xb9\0" }, + { 0x1fc1, "\x00\xa8\x03\x42\0" }, + { 0x1fc2, "\x03\xb7\x03\x00\x03\x45\0" }, + { 0x1fc3, "\x03\xb7\x03\x45\0" }, + { 0x1fc4, "\x03\xb7\x03\x01\x03\x45\0" }, + { 0x1fc6, "\x03\xb7\x03\x42\0" }, + { 0x1fc7, "\x03\xb7\x03\x42\x03\x45\0" }, + { 0x1fc8, "\x03\x95\x03\x00\0" }, + { 0x1fc9, "\x03\x95\x03\x01\0" }, + { 0x1fca, "\x03\x97\x03\x00\0" }, + { 0x1fcb, "\x03\x97\x03\x01\0" }, + { 0x1fcc, "\x03\x97\x03\x45\0" }, + { 0x1fcd, "\x1f\xbf\x03\x00\0" }, + { 0x1fce, "\x1f\xbf\x03\x01\0" }, + { 0x1fcf, "\x1f\xbf\x03\x42\0" }, + { 0x1fd0, "\x03\xb9\x03\x06\0" }, + { 0x1fd1, "\x03\xb9\x03\x04\0" }, + { 0x1fd2, "\x03\xb9\x03\x08\x03\x00\0" }, + { 0x1fd3, "\x03\xb9\x03\x08\x03\x01\0" }, + { 0x1fd6, "\x03\xb9\x03\x42\0" }, + { 0x1fd7, "\x03\xb9\x03\x08\x03\x42\0" }, + { 0x1fd8, "\x03\x99\x03\x06\0" }, + { 0x1fd9, "\x03\x99\x03\x04\0" }, + { 0x1fda, "\x03\x99\x03\x00\0" }, + { 0x1fdb, "\x03\x99\x03\x01\0" }, + { 0x1fdd, "\x1f\xfe\x03\x00\0" }, + { 0x1fde, "\x1f\xfe\x03\x01\0" }, + { 0x1fdf, "\x1f\xfe\x03\x42\0" }, + { 0x1fe0, "\x03\xc5\x03\x06\0" }, + { 0x1fe1, "\x03\xc5\x03\x04\0" }, + { 0x1fe2, "\x03\xc5\x03\x08\x03\x00\0" }, + { 0x1fe3, "\x03\xc5\x03\x08\x03\x01\0" }, + { 0x1fe4, "\x03\xc1\x03\x13\0" }, + { 0x1fe5, "\x03\xc1\x03\x14\0" }, + { 0x1fe6, "\x03\xc5\x03\x42\0" }, + { 0x1fe7, "\x03\xc5\x03\x08\x03\x42\0" }, + { 0x1fe8, "\x03\xa5\x03\x06\0" }, + { 0x1fe9, "\x03\xa5\x03\x04\0" }, + { 0x1fea, "\x03\xa5\x03\x00\0" }, + { 0x1feb, "\x03\xa5\x03\x01\0" }, + { 0x1fec, "\x03\xa1\x03\x14\0" }, + { 0x1fed, "\x00\xa8\x03\x00\0" }, + { 0x1fee, "\x00\xa8\x03\x01\0" }, + { 0x1fef, "\x00\x60\0" }, + { 0x1ff2, "\x03\xc9\x03\x00\x03\x45\0" }, + { 0x1ff3, "\x03\xc9\x03\x45\0" }, + { 0x1ff4, "\x03\xc9\x03\x01\x03\x45\0" }, + { 0x1ff6, "\x03\xc9\x03\x42\0" }, + { 0x1ff7, "\x03\xc9\x03\x42\x03\x45\0" }, + { 0x1ff8, "\x03\x9f\x03\x00\0" }, + { 0x1ff9, "\x03\x9f\x03\x01\0" }, + { 0x1ffa, "\x03\xa9\x03\x00\0" }, + { 0x1ffb, "\x03\xa9\x03\x01\0" }, + { 0x1ffc, "\x03\xa9\x03\x45\0" }, + { 0x1ffd, "\x00\xb4\0" }, + { 0x2000, "\x20\x02\0" }, + { 0x2001, "\x20\x03\0" }, + { 0x2126, "\x03\xa9\0" }, + { 0x212a, "\x00\x4b\0" }, + { 0x212b, "\x00\x41\x03\x0a\0" }, + { 0x2204, "\x22\x03\x03\x38\0" }, + { 0x2209, "\x22\x08\x03\x38\0" }, + { 0x220c, "\x22\x0b\x03\x38\0" }, + { 0x2224, "\x22\x23\x03\x38\0" }, + { 0x2226, "\x22\x25\x03\x38\0" }, + { 0x2241, "\x00\x7e\x03\x38\0" }, + { 0x2244, "\x22\x43\x03\x38\0" }, + { 0x2247, "\x22\x45\x03\x38\0" }, + { 0x2249, "\x22\x48\x03\x38\0" }, + { 0x2260, "\x00\x3d\x03\x38\0" }, + { 0x2262, "\x22\x61\x03\x38\0" }, + { 0x226d, "\x22\x4d\x03\x38\0" }, + { 0x226e, "\x00\x3c\x03\x38\0" }, + { 0x226f, "\x00\x3e\x03\x38\0" }, + { 0x2270, "\x22\x64\x03\x38\0" }, + { 0x2271, "\x22\x65\x03\x38\0" }, + { 0x2274, "\x22\x72\x03\x38\0" }, + { 0x2275, "\x22\x73\x03\x38\0" }, + { 0x2278, "\x22\x76\x03\x38\0" }, + { 0x2279, "\x22\x77\x03\x38\0" }, + { 0x2280, "\x22\x7a\x03\x38\0" }, + { 0x2281, "\x22\x7b\x03\x38\0" }, + { 0x2284, "\x22\x82\x03\x38\0" }, + { 0x2285, "\x22\x83\x03\x38\0" }, + { 0x2288, "\x22\x86\x03\x38\0" }, + { 0x2289, "\x22\x87\x03\x38\0" }, + { 0x22ac, "\x22\xa2\x03\x38\0" }, + { 0x22ad, "\x22\xa8\x03\x38\0" }, + { 0x22ae, "\x22\xa9\x03\x38\0" }, + { 0x22af, "\x22\xab\x03\x38\0" }, + { 0x22e0, "\x22\x7c\x03\x38\0" }, + { 0x22e1, "\x22\x7d\x03\x38\0" }, + { 0x22e2, "\x22\x91\x03\x38\0" }, + { 0x22e3, "\x22\x92\x03\x38\0" }, + { 0x22ea, "\x22\xb2\x03\x38\0" }, + { 0x22eb, "\x22\xb3\x03\x38\0" }, + { 0x22ec, "\x22\xb4\x03\x38\0" }, + { 0x22ed, "\x22\xb5\x03\x38\0" }, + { 0x2329, "\x30\x08\0" }, + { 0x232a, "\x30\x09\0" }, + { 0x304c, "\x30\x4b\x30\x99\0" }, + { 0x304e, "\x30\x4d\x30\x99\0" }, + { 0x3050, "\x30\x4f\x30\x99\0" }, + { 0x3052, "\x30\x51\x30\x99\0" }, + { 0x3054, "\x30\x53\x30\x99\0" }, + { 0x3056, "\x30\x55\x30\x99\0" }, + { 0x3058, "\x30\x57\x30\x99\0" }, + { 0x305a, "\x30\x59\x30\x99\0" }, + { 0x305c, "\x30\x5b\x30\x99\0" }, + { 0x305e, "\x30\x5d\x30\x99\0" }, + { 0x3060, "\x30\x5f\x30\x99\0" }, + { 0x3062, "\x30\x61\x30\x99\0" }, + { 0x3065, "\x30\x64\x30\x99\0" }, + { 0x3067, "\x30\x66\x30\x99\0" }, + { 0x3069, "\x30\x68\x30\x99\0" }, + { 0x3070, "\x30\x6f\x30\x99\0" }, + { 0x3071, "\x30\x6f\x30\x9a\0" }, + { 0x3073, "\x30\x72\x30\x99\0" }, + { 0x3074, "\x30\x72\x30\x9a\0" }, + { 0x3076, "\x30\x75\x30\x99\0" }, + { 0x3077, "\x30\x75\x30\x9a\0" }, + { 0x3079, "\x30\x78\x30\x99\0" }, + { 0x307a, "\x30\x78\x30\x9a\0" }, + { 0x307c, "\x30\x7b\x30\x99\0" }, + { 0x307d, "\x30\x7b\x30\x9a\0" }, + { 0x3094, "\x30\x46\x30\x99\0" }, + { 0x309e, "\x30\x9d\x30\x99\0" }, + { 0x30ac, "\x30\xab\x30\x99\0" }, + { 0x30ae, "\x30\xad\x30\x99\0" }, + { 0x30b0, "\x30\xaf\x30\x99\0" }, + { 0x30b2, "\x30\xb1\x30\x99\0" }, + { 0x30b4, "\x30\xb3\x30\x99\0" }, + { 0x30b6, "\x30\xb5\x30\x99\0" }, + { 0x30b8, "\x30\xb7\x30\x99\0" }, + { 0x30ba, "\x30\xb9\x30\x99\0" }, + { 0x30bc, "\x30\xbb\x30\x99\0" }, + { 0x30be, "\x30\xbd\x30\x99\0" }, + { 0x30c0, "\x30\xbf\x30\x99\0" }, + { 0x30c2, "\x30\xc1\x30\x99\0" }, + { 0x30c5, "\x30\xc4\x30\x99\0" }, + { 0x30c7, "\x30\xc6\x30\x99\0" }, + { 0x30c9, "\x30\xc8\x30\x99\0" }, + { 0x30d0, "\x30\xcf\x30\x99\0" }, + { 0x30d1, "\x30\xcf\x30\x9a\0" }, + { 0x30d3, "\x30\xd2\x30\x99\0" }, + { 0x30d4, "\x30\xd2\x30\x9a\0" }, + { 0x30d6, "\x30\xd5\x30\x99\0" }, + { 0x30d7, "\x30\xd5\x30\x9a\0" }, + { 0x30d9, "\x30\xd8\x30\x99\0" }, + { 0x30da, "\x30\xd8\x30\x9a\0" }, + { 0x30dc, "\x30\xdb\x30\x99\0" }, + { 0x30dd, "\x30\xdb\x30\x9a\0" }, + { 0x30f4, "\x30\xa6\x30\x99\0" }, + { 0x30f7, "\x30\xef\x30\x99\0" }, + { 0x30f8, "\x30\xf0\x30\x99\0" }, + { 0x30f9, "\x30\xf1\x30\x99\0" }, + { 0x30fa, "\x30\xf2\x30\x99\0" }, + { 0x30fe, "\x30\xfd\x30\x99\0" }, + { 0xf900, "\x8c\x48\0" }, + { 0xf901, "\x66\xf4\0" }, + { 0xf902, "\x8e\xca\0" }, + { 0xf903, "\x8c\xc8\0" }, + { 0xf904, "\x6e\xd1\0" }, + { 0xf905, "\x4e\x32\0" }, + { 0xf906, "\x53\xe5\0" }, + { 0xf907, "\x9f\x9c\0" }, + { 0xf908, "\x9f\x9c\0" }, + { 0xf909, "\x59\x51\0" }, + { 0xf90a, "\x91\xd1\0" }, + { 0xf90b, "\x55\x87\0" }, + { 0xf90c, "\x59\x48\0" }, + { 0xf90d, "\x61\xf6\0" }, + { 0xf90e, "\x76\x69\0" }, + { 0xf90f, "\x7f\x85\0" }, + { 0xf910, "\x86\x3f\0" }, + { 0xf911, "\x87\xba\0" }, + { 0xf912, "\x88\xf8\0" }, + { 0xf913, "\x90\x8f\0" }, + { 0xf914, "\x6a\x02\0" }, + { 0xf915, "\x6d\x1b\0" }, + { 0xf916, "\x70\xd9\0" }, + { 0xf917, "\x73\xde\0" }, + { 0xf918, "\x84\x3d\0" }, + { 0xf919, "\x91\x6a\0" }, + { 0xf91a, "\x99\xf1\0" }, + { 0xf91b, "\x4e\x82\0" }, + { 0xf91c, "\x53\x75\0" }, + { 0xf91d, "\x6b\x04\0" }, + { 0xf91e, "\x72\x1b\0" }, + { 0xf91f, "\x86\x2d\0" }, + { 0xf920, "\x9e\x1e\0" }, + { 0xf921, "\x5d\x50\0" }, + { 0xf922, "\x6f\xeb\0" }, + { 0xf923, "\x85\xcd\0" }, + { 0xf924, "\x89\x64\0" }, + { 0xf925, "\x62\xc9\0" }, + { 0xf926, "\x81\xd8\0" }, + { 0xf927, "\x88\x1f\0" }, + { 0xf928, "\x5e\xca\0" }, + { 0xf929, "\x67\x17\0" }, + { 0xf92a, "\x6d\x6a\0" }, + { 0xf92b, "\x72\xfc\0" }, + { 0xf92c, "\x90\xce\0" }, + { 0xf92d, "\x4f\x86\0" }, + { 0xf92e, "\x51\xb7\0" }, + { 0xf92f, "\x52\xde\0" }, + { 0xf930, "\x64\xc4\0" }, + { 0xf931, "\x6a\xd3\0" }, + { 0xf932, "\x72\x10\0" }, + { 0xf933, "\x76\xe7\0" }, + { 0xf934, "\x80\x01\0" }, + { 0xf935, "\x86\x06\0" }, + { 0xf936, "\x86\x5c\0" }, + { 0xf937, "\x8d\xef\0" }, + { 0xf938, "\x97\x32\0" }, + { 0xf939, "\x9b\x6f\0" }, + { 0xf93a, "\x9d\xfa\0" }, + { 0xf93b, "\x78\x8c\0" }, + { 0xf93c, "\x79\x7f\0" }, + { 0xf93d, "\x7d\xa0\0" }, + { 0xf93e, "\x83\xc9\0" }, + { 0xf93f, "\x93\x04\0" }, + { 0xf940, "\x9e\x7f\0" }, + { 0xf941, "\x8a\xd6\0" }, + { 0xf942, "\x58\xdf\0" }, + { 0xf943, "\x5f\x04\0" }, + { 0xf944, "\x7c\x60\0" }, + { 0xf945, "\x80\x7e\0" }, + { 0xf946, "\x72\x62\0" }, + { 0xf947, "\x78\xca\0" }, + { 0xf948, "\x8c\xc2\0" }, + { 0xf949, "\x96\xf7\0" }, + { 0xf94a, "\x58\xd8\0" }, + { 0xf94b, "\x5c\x62\0" }, + { 0xf94c, "\x6a\x13\0" }, + { 0xf94d, "\x6d\xda\0" }, + { 0xf94e, "\x6f\x0f\0" }, + { 0xf94f, "\x7d\x2f\0" }, + { 0xf950, "\x7e\x37\0" }, + { 0xf951, "\x96\xfb\0" }, + { 0xf952, "\x52\xd2\0" }, + { 0xf953, "\x80\x8b\0" }, + { 0xf954, "\x51\xdc\0" }, + { 0xf955, "\x51\xcc\0" }, + { 0xf956, "\x7a\x1c\0" }, + { 0xf957, "\x7d\xbe\0" }, + { 0xf958, "\x83\xf1\0" }, + { 0xf959, "\x96\x75\0" }, + { 0xf95a, "\x8b\x80\0" }, + { 0xf95b, "\x62\xcf\0" }, + { 0xf95c, "\x6a\x02\0" }, + { 0xf95d, "\x8a\xfe\0" }, + { 0xf95e, "\x4e\x39\0" }, + { 0xf95f, "\x5b\xe7\0" }, + { 0xf960, "\x60\x12\0" }, + { 0xf961, "\x73\x87\0" }, + { 0xf962, "\x75\x70\0" }, + { 0xf963, "\x53\x17\0" }, + { 0xf964, "\x78\xfb\0" }, + { 0xf965, "\x4f\xbf\0" }, + { 0xf966, "\x5f\xa9\0" }, + { 0xf967, "\x4e\x0d\0" }, + { 0xf968, "\x6c\xcc\0" }, + { 0xf969, "\x65\x78\0" }, + { 0xf96a, "\x7d\x22\0" }, + { 0xf96b, "\x53\xc3\0" }, + { 0xf96c, "\x58\x5e\0" }, + { 0xf96d, "\x77\x01\0" }, + { 0xf96e, "\x84\x49\0" }, + { 0xf96f, "\x8a\xaa\0" }, + { 0xf970, "\x6b\xba\0" }, + { 0xf971, "\x8f\xb0\0" }, + { 0xf972, "\x6c\x88\0" }, + { 0xf973, "\x62\xfe\0" }, + { 0xf974, "\x82\xe5\0" }, + { 0xf975, "\x63\xa0\0" }, + { 0xf976, "\x75\x65\0" }, + { 0xf977, "\x4e\xae\0" }, + { 0xf978, "\x51\x69\0" }, + { 0xf979, "\x51\xc9\0" }, + { 0xf97a, "\x68\x81\0" }, + { 0xf97b, "\x7c\xe7\0" }, + { 0xf97c, "\x82\x6f\0" }, + { 0xf97d, "\x8a\xd2\0" }, + { 0xf97e, "\x91\xcf\0" }, + { 0xf97f, "\x52\xf5\0" }, + { 0xf980, "\x54\x42\0" }, + { 0xf981, "\x59\x73\0" }, + { 0xf982, "\x5e\xec\0" }, + { 0xf983, "\x65\xc5\0" }, + { 0xf984, "\x6f\xfe\0" }, + { 0xf985, "\x79\x2a\0" }, + { 0xf986, "\x95\xad\0" }, + { 0xf987, "\x9a\x6a\0" }, + { 0xf988, "\x9e\x97\0" }, + { 0xf989, "\x9e\xce\0" }, + { 0xf98a, "\x52\x9b\0" }, + { 0xf98b, "\x66\xc6\0" }, + { 0xf98c, "\x6b\x77\0" }, + { 0xf98d, "\x8f\x62\0" }, + { 0xf98e, "\x5e\x74\0" }, + { 0xf98f, "\x61\x90\0" }, + { 0xf990, "\x62\x00\0" }, + { 0xf991, "\x64\x9a\0" }, + { 0xf992, "\x6f\x23\0" }, + { 0xf993, "\x71\x49\0" }, + { 0xf994, "\x74\x89\0" }, + { 0xf995, "\x79\xca\0" }, + { 0xf996, "\x7d\xf4\0" }, + { 0xf997, "\x80\x6f\0" }, + { 0xf998, "\x8f\x26\0" }, + { 0xf999, "\x84\xee\0" }, + { 0xf99a, "\x90\x23\0" }, + { 0xf99b, "\x93\x4a\0" }, + { 0xf99c, "\x52\x17\0" }, + { 0xf99d, "\x52\xa3\0" }, + { 0xf99e, "\x54\xbd\0" }, + { 0xf99f, "\x70\xc8\0" }, + { 0xf9a0, "\x88\xc2\0" }, + { 0xf9a1, "\x8a\xaa\0" }, + { 0xf9a2, "\x5e\xc9\0" }, + { 0xf9a3, "\x5f\xf5\0" }, + { 0xf9a4, "\x63\x7b\0" }, + { 0xf9a5, "\x6b\xae\0" }, + { 0xf9a6, "\x7c\x3e\0" }, + { 0xf9a7, "\x73\x75\0" }, + { 0xf9a8, "\x4e\xe4\0" }, + { 0xf9a9, "\x56\xf9\0" }, + { 0xf9aa, "\x5b\xe7\0" }, + { 0xf9ab, "\x5d\xba\0" }, + { 0xf9ac, "\x60\x1c\0" }, + { 0xf9ad, "\x73\xb2\0" }, + { 0xf9ae, "\x74\x69\0" }, + { 0xf9af, "\x7f\x9a\0" }, + { 0xf9b0, "\x80\x46\0" }, + { 0xf9b1, "\x92\x34\0" }, + { 0xf9b2, "\x96\xf6\0" }, + { 0xf9b3, "\x97\x48\0" }, + { 0xf9b4, "\x98\x18\0" }, + { 0xf9b5, "\x4f\x8b\0" }, + { 0xf9b6, "\x79\xae\0" }, + { 0xf9b7, "\x91\xb4\0" }, + { 0xf9b8, "\x96\xb8\0" }, + { 0xf9b9, "\x60\xe1\0" }, + { 0xf9ba, "\x4e\x86\0" }, + { 0xf9bb, "\x50\xda\0" }, + { 0xf9bc, "\x5b\xee\0" }, + { 0xf9bd, "\x5c\x3f\0" }, + { 0xf9be, "\x65\x99\0" }, + { 0xf9bf, "\x6a\x02\0" }, + { 0xf9c0, "\x71\xce\0" }, + { 0xf9c1, "\x76\x42\0" }, + { 0xf9c2, "\x84\xfc\0" }, + { 0xf9c3, "\x90\x7c\0" }, + { 0xf9c4, "\x9f\x8d\0" }, + { 0xf9c5, "\x66\x88\0" }, + { 0xf9c6, "\x96\x2e\0" }, + { 0xf9c7, "\x52\x89\0" }, + { 0xf9c8, "\x67\x7b\0" }, + { 0xf9c9, "\x67\xf3\0" }, + { 0xf9ca, "\x6d\x41\0" }, + { 0xf9cb, "\x6e\x9c\0" }, + { 0xf9cc, "\x74\x09\0" }, + { 0xf9cd, "\x75\x59\0" }, + { 0xf9ce, "\x78\x6b\0" }, + { 0xf9cf, "\x7d\x10\0" }, + { 0xf9d0, "\x98\x5e\0" }, + { 0xf9d1, "\x51\x6d\0" }, + { 0xf9d2, "\x62\x2e\0" }, + { 0xf9d3, "\x96\x78\0" }, + { 0xf9d4, "\x50\x2b\0" }, + { 0xf9d5, "\x5d\x19\0" }, + { 0xf9d6, "\x6d\xea\0" }, + { 0xf9d7, "\x8f\x2a\0" }, + { 0xf9d8, "\x5f\x8b\0" }, + { 0xf9d9, "\x61\x44\0" }, + { 0xf9da, "\x68\x17\0" }, + { 0xf9db, "\x73\x87\0" }, + { 0xf9dc, "\x96\x86\0" }, + { 0xf9dd, "\x52\x29\0" }, + { 0xf9de, "\x54\x0f\0" }, + { 0xf9df, "\x5c\x65\0" }, + { 0xf9e0, "\x66\x13\0" }, + { 0xf9e1, "\x67\x4e\0" }, + { 0xf9e2, "\x68\xa8\0" }, + { 0xf9e3, "\x6c\xe5\0" }, + { 0xf9e4, "\x74\x06\0" }, + { 0xf9e5, "\x75\xe2\0" }, + { 0xf9e6, "\x7f\x79\0" }, + { 0xf9e7, "\x88\xcf\0" }, + { 0xf9e8, "\x88\xe1\0" }, + { 0xf9e9, "\x91\xcc\0" }, + { 0xf9ea, "\x96\xe2\0" }, + { 0xf9eb, "\x53\x3f\0" }, + { 0xf9ec, "\x6e\xba\0" }, + { 0xf9ed, "\x54\x1d\0" }, + { 0xf9ee, "\x71\xd0\0" }, + { 0xf9ef, "\x74\x98\0" }, + { 0xf9f0, "\x85\xfa\0" }, + { 0xf9f1, "\x96\xa3\0" }, + { 0xf9f2, "\x9c\x57\0" }, + { 0xf9f3, "\x9e\x9f\0" }, + { 0xf9f4, "\x67\x97\0" }, + { 0xf9f5, "\x6d\xcb\0" }, + { 0xf9f6, "\x81\xe8\0" }, + { 0xf9f7, "\x7a\xcb\0" }, + { 0xf9f8, "\x7b\x20\0" }, + { 0xf9f9, "\x7c\x92\0" }, + { 0xf9fa, "\x72\xc0\0" }, + { 0xf9fb, "\x70\x99\0" }, + { 0xf9fc, "\x8b\x58\0" }, + { 0xf9fd, "\x4e\xc0\0" }, + { 0xf9fe, "\x83\x36\0" }, + { 0xf9ff, "\x52\x3a\0" }, + { 0xfa00, "\x52\x07\0" }, + { 0xfa01, "\x5e\xa6\0" }, + { 0xfa02, "\x62\xd3\0" }, + { 0xfa03, "\x7c\xd6\0" }, + { 0xfa04, "\x5b\x85\0" }, + { 0xfa05, "\x6d\x1e\0" }, + { 0xfa06, "\x66\xb4\0" }, + { 0xfa07, "\x8f\x3b\0" }, + { 0xfa08, "\x88\x4c\0" }, + { 0xfa09, "\x96\x4d\0" }, + { 0xfa0a, "\x89\x8b\0" }, + { 0xfa0b, "\x5e\xd3\0" }, + { 0xfa0c, "\x51\x40\0" }, + { 0xfa0d, "\x55\xc0\0" }, + { 0xfa10, "\x58\x5a\0" }, + { 0xfa12, "\x66\x74\0" }, + { 0xfa15, "\x51\xde\0" }, + { 0xfa16, "\x73\x2a\0" }, + { 0xfa17, "\x76\xca\0" }, + { 0xfa18, "\x79\x3c\0" }, + { 0xfa19, "\x79\x5e\0" }, + { 0xfa1a, "\x79\x65\0" }, + { 0xfa1b, "\x79\x8f\0" }, + { 0xfa1c, "\x97\x56\0" }, + { 0xfa1d, "\x7c\xbe\0" }, + { 0xfa1e, "\x7f\xbd\0" }, + { 0xfa20, "\x86\x12\0" }, + { 0xfa22, "\x8a\xf8\0" }, + { 0xfa25, "\x90\x38\0" }, + { 0xfa26, "\x90\xfd\0" }, + { 0xfa2a, "\x98\xef\0" }, + { 0xfa2b, "\x98\xfc\0" }, + { 0xfa2c, "\x99\x28\0" }, + { 0xfa2d, "\x9d\xb4\0" }, + { 0xfb1f, "\x05\xf2\x05\xb7\0" }, + { 0xfb2a, "\x05\xe9\x05\xc1\0" }, + { 0xfb2b, "\x05\xe9\x05\xc2\0" }, + { 0xfb2c, "\x05\xe9\x05\xbc\x05\xc1\0" }, + { 0xfb2d, "\x05\xe9\x05\xbc\x05\xc2\0" }, + { 0xfb2e, "\x05\xd0\x05\xb7\0" }, + { 0xfb2f, "\x05\xd0\x05\xb8\0" }, + { 0xfb30, "\x05\xd0\x05\xbc\0" }, + { 0xfb31, "\x05\xd1\x05\xbc\0" }, + { 0xfb32, "\x05\xd2\x05\xbc\0" }, + { 0xfb33, "\x05\xd3\x05\xbc\0" }, + { 0xfb34, "\x05\xd4\x05\xbc\0" }, + { 0xfb35, "\x05\xd5\x05\xbc\0" }, + { 0xfb36, "\x05\xd6\x05\xbc\0" }, + { 0xfb38, "\x05\xd8\x05\xbc\0" }, + { 0xfb39, "\x05\xd9\x05\xbc\0" }, + { 0xfb3a, "\x05\xda\x05\xbc\0" }, + { 0xfb3b, "\x05\xdb\x05\xbc\0" }, + { 0xfb3c, "\x05\xdc\x05\xbc\0" }, + { 0xfb3e, "\x05\xde\x05\xbc\0" }, + { 0xfb40, "\x05\xe0\x05\xbc\0" }, + { 0xfb41, "\x05\xe1\x05\xbc\0" }, + { 0xfb43, "\x05\xe3\x05\xbc\0" }, + { 0xfb44, "\x05\xe4\x05\xbc\0" }, + { 0xfb46, "\x05\xe6\x05\xbc\0" }, + { 0xfb47, "\x05\xe7\x05\xbc\0" }, + { 0xfb48, "\x05\xe8\x05\xbc\0" }, + { 0xfb49, "\x05\xe9\x05\xbc\0" }, + { 0xfb4a, "\x05\xea\x05\xbc\0" }, + { 0xfb4b, "\x05\xd5\x05\xb9\0" }, + { 0xfb4c, "\x05\xd1\x05\xbf\0" }, + { 0xfb4d, "\x05\xdb\x05\xbf\0" }, + { 0xfb4e, "\x05\xe4\x05\xbf\0" } +}; + +/* + * WARNING! + * + * NO BUFFER CHECKING AHEAD! + * + */ + +static gint +e_canonical_decomposition (gunichar ch, gunichar * buf) +{ + gint len = 0; + + if (ch <= 0xffff) + { + int start = 0; + int end = sizeof (e_decomp_table) / sizeof (e_decomp_table[0]); + while (start != end) + { + int half = (start + end) / 2; + if (ch == e_decomp_table[half].ch) { + /* Found it. */ + int i; + /* We store as a double-nul terminated string. */ + for (len = 0; (e_decomp_table[half].expansion[len] || e_decomp_table[half].expansion[len + 1]); len += 2) ; + + /* We've counted twice as many bytes as there are + characters. */ + len /= 2; + + for (i = 0; i < len; i ++) { + buf[i] = (e_decomp_table[half].expansion[2 * i] << 8) | e_decomp_table[half].expansion[2 * i + 1]; + } + break; + } else if (ch > e_decomp_table[half].ch) { + if (start == half) break; + start = half; + } else { + if (end == half) break; + end = half; + } + } + } + + if (len == 0) + { + /* Not in our table. */ + *buf = ch; + len = 1; + } + + /* Supposedly following the Unicode 2.1.9 table means that the + decompositions come out in canonical order. I haven't tested + this, but we rely on it here. */ + return len; +} + +static gunichar +e_stripped_char (gunichar ch) +{ + gunichar decomp[MAX_DECOMP]; + GUnicodeType utype; + gint dlen; + + utype = g_unichar_type (ch); + + switch (utype) { + case G_UNICODE_CONTROL: + case G_UNICODE_FORMAT: + case G_UNICODE_UNASSIGNED: + case G_UNICODE_COMBINING_MARK: + /* Ignore those */ + return 0; + default: + /* Convert to lowercase, fall through */ + ch = g_unichar_tolower (ch); + case G_UNICODE_LOWERCASE_LETTER: + dlen = e_canonical_decomposition (ch, decomp); + if (dlen > 0) return *decomp; + break; + } + + return 0; +} + +gchar * +e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name) +{ + xmlChar *prop; + gchar *ret_val = NULL; + gchar *combined_name; + + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (prop_name != NULL, NULL); + + prop = xmlGetProp ((xmlNode *) parent, prop_name); + if (prop != NULL) { + ret_val = g_strdup ((char *)prop); + xmlFree (prop); + return ret_val; + } + + combined_name = g_strdup_printf("_%s", prop_name); + prop = xmlGetProp ((xmlNode *) parent, (unsigned char *)combined_name); + if (prop != NULL) { + ret_val = g_strdup (gettext ((char *)prop)); + xmlFree (prop); + } + g_free(combined_name); + + return ret_val; +} diff --git a/e-util/e-unicode.h b/e-util/e-unicode.h new file mode 100644 index 0000000000..b745876b6d --- /dev/null +++ b/e-util/e-unicode.h @@ -0,0 +1,113 @@ +/* + * e-unicode.h - utf-8 support functions for gal + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Authors: + * Lauris Kaplinski <lauris@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _E_UNICODE_H_ +#define _E_UNICODE_H_ + +#include <sys/types.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <libxml/tree.h> +#include <iconv.h> + +G_BEGIN_DECLS + +#define G_UTF8_IN_GAL + +/* + * UTF-8 searching implementations + * + * e_utf8_strstrcase - case insensitive search + * e_utf8_strstrcasedecomp - case insensitive and decompositing search (i.e. accented + * letters are treated equal to their base letters, explicit accent marks (unicode + * not ascii/iso ones) are ignored). + */ + +const gchar *e_utf8_strstrcase (const gchar *haystack, + const gchar *needle); +const gchar *e_utf8_strstrcasedecomp (const gchar *haystack, + const gchar *needle); +gchar *e_utf8_from_gtk_event_key (GtkWidget *widget, + guint keyval, + const gchar *string); +gchar *e_utf8_from_iconv_string (iconv_t ic, + const gchar *string); +gchar *e_utf8_from_iconv_string_sized (iconv_t ic, + const gchar *string, + gint bytes); +gchar *e_utf8_to_iconv_string (iconv_t ic, + const gchar *string); +gchar *e_utf8_to_iconv_string_sized (iconv_t ic, + const gchar *string, + gint bytes); +gchar *e_utf8_from_charset_string (const gchar *charset, + const gchar *string); +gchar *e_utf8_from_charset_string_sized (const gchar *charset, + const gchar *string, + gint bytes); +gchar *e_utf8_to_charset_string (const gchar *charset, + const gchar *string); +gchar *e_utf8_to_charset_string_sized (const gchar *charset, + const gchar *string, + gint bytes); +gchar *e_utf8_from_locale_string (const gchar *string); +gchar *e_utf8_from_locale_string_sized (const gchar *string, + gint bytes); +gchar *e_utf8_to_locale_string (const gchar *string); +gchar *e_utf8_to_locale_string_sized (const gchar *string, + gint bytes); +gboolean e_utf8_is_ascii (const gchar *string); +/* + * These are simple wrappers that save us some typing + */ + +/* NB! This return newly allocated string, not const as gtk+ one */ +gchar *e_utf8_gtk_entry_get_text (GtkEntry *entry); +void e_utf8_gtk_entry_set_text (GtkEntry *entry, + const gchar *text); +gchar *e_utf8_gtk_editable_get_text (GtkEditable *editable); +void e_utf8_gtk_editable_set_text (GtkEditable *editable, + const gchar *text); +gchar *e_utf8_gtk_editable_get_chars (GtkEditable *editable, + gint start, + gint end); +void e_utf8_gtk_editable_insert_text (GtkEditable *editable, + const gchar *text, + gint length, + gint *position); +gchar *e_utf8_xml1_decode (const gchar *text); +gchar *e_utf8_xml1_encode (const gchar *text); +gint e_unichar_to_utf8 (gint c, + gchar *outbuf); +gchar *e_unicode_get_utf8 (const gchar *text, + gunichar *out); +guint32 gdk_keyval_to_unicode (guint keysym); +gchar *e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, + const xmlChar *prop_name); + +G_END_DECLS + +#endif + + diff --git a/e-util/e-util-labels.c b/e-util/e-util-labels.c deleted file mode 100644 index 85984da59c..0000000000 --- a/e-util/e-util-labels.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Authors: - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include <gtk/gtk.h> -#include <glib/gi18n.h> - -#include <stdio.h> -#include <string.h> - -#include <gconf/gconf-client.h> - -#include <camel/camel-utf8.h> - -#include "e-util.h" -#include "e-util-labels.h" -#include "e-dialog-utils.h" -#include "filter/filter-option.h" - -/* Note, the first element of each EUtilLabel must NOT be translated */ -EUtilLabel label_defaults[LABEL_DEFAULTS_NUM] = { - { "$Labelimportant", N_("I_mportant"), "#EF2929" }, /* red */ - { "$Labelwork", N_("_Work"), "#F57900" }, /* orange */ - { "$Labelpersonal", N_("_Personal"), "#4E9A06" }, /* green */ - { "$Labeltodo", N_("_To Do"), "#3465A4" }, /* blue */ - { "$Labellater", N_("_Later"), "#75507B" } /* purple */ -}; - -/** - * e_util_labels_parse - * Reads the setup from client and parses it to list of EUtilLabel objects. - * - * @param client The config client to be used for reading setup. - * Can be NULL, in that case it will use the default client. - * @return Newly allocated list of labels, should be freed with @ref e_util_labels_free. - **/ -GSList * -e_util_labels_parse (GConfClient *client) -{ - GSList *labels, *list, *head; - EUtilLabel *label; - char *buf; - int num = 0; - gboolean unref_client = client == NULL; - - labels = NULL; - - if (!client) - client = gconf_client_get_default (); - - head = gconf_client_get_list (client, E_UTIL_LABELS_GCONF_KEY, GCONF_VALUE_STRING, NULL); - - for (list = head; list; list = list->next) { - char *color, *name, *tag; - name = buf = list->data; - color = strrchr (buf, ':'); - if (color == NULL) { - g_free (buf); - continue; - } - - *color++ = '\0'; - tag = strchr (color, '|'); - if (tag) - *tag++ = '\0'; - - label = g_new (EUtilLabel, 1); - - /* Needed for Backward Compatibility */ - if (num < LABEL_DEFAULTS_NUM) { - label->name = g_strdup ((buf && *buf) ? buf : _(label_defaults[num].name)); - label->tag = g_strdup (label_defaults[num].tag); - num++; - } else if (!tag) { - g_free (buf); - g_free (label); - continue; - } else { - label->name = g_strdup (name); - label->tag = g_strdup (tag); - } - - label->colour = g_strdup (color); - labels = g_slist_prepend (labels, label); - - g_free (buf); - } - - if (head) - g_slist_free (head); - - while (num < LABEL_DEFAULTS_NUM) { - /* complete the list with defaults */ - label = g_new (EUtilLabel, 1); - label->tag = g_strdup (label_defaults[num].tag); - label->name = g_strdup (_(label_defaults[num].name)); - label->colour = g_strdup (label_defaults[num].colour); - - labels = g_slist_prepend (labels, label); - - num++; - } - - if (unref_client) - g_object_unref (client); - - return g_slist_reverse (labels); -} - -static void -free_label_struct (EUtilLabel *label) -{ - if (!label) - return; - - g_free (label->tag); - g_free (label->name); - g_free (label->colour); - g_free (label); -} - -/** - * e_util_labels_free - * Frees memory previously allocated by @ref e_util_labels_parse - * - * @param labels Labels list, previously allocated by @ref e_util_labels_parse - * It is safe to call with NULL. - **/ -void -e_util_labels_free (GSList *labels) -{ - if (!labels) - return; - - g_slist_foreach (labels, (GFunc)free_label_struct, NULL); - g_slist_free (labels); -} - -/* stores the actual cache to gconf */ -static gboolean -flush_labels_cache (GSList *labels, gboolean free_labels) -{ - GSList *l, *text_labels; - GConfClient *client; - - if (!labels) - return FALSE; - - text_labels = NULL; - - for (l = labels; l; l = l->next) { - EUtilLabel *label = l->data; - - if (label && label->tag && label->name && label->colour) - text_labels = g_slist_prepend (text_labels, g_strdup_printf ("%s:%s|%s", label->name, label->colour, label->tag)); - } - - if (!text_labels) { - if (free_labels) - e_util_labels_free (labels); - - return FALSE; - } - - text_labels = g_slist_reverse (text_labels); - - client = gconf_client_get_default (); - gconf_client_set_list (client, E_UTIL_LABELS_GCONF_KEY, GCONF_VALUE_STRING, text_labels, NULL); - g_object_unref (client); - - g_slist_foreach (text_labels, (GFunc)g_free, NULL); - g_slist_free (text_labels); - - if (free_labels) - e_util_labels_free (labels); - - /* not true if gconf failed to write; who cares */ - return TRUE; -} - -/** - * find_label - * - * Looks for label in labels cache by tag and returns actual pointer to cache. - * @param labels The cache of labels; comes from @ref e_util_labels_parse - * @param tag Tag of label you are looking for. - * @return Pointer to cache data if label with such tag exists or NULL. Do not free it! - **/ -static EUtilLabel * -find_label (GSList *labels, const char *tag) -{ - GSList *l; - - g_return_val_if_fail (tag != NULL, NULL); - - for (l = labels; l; l = l->next) { - EUtilLabel *label = l->data; - - if (label && label->tag && !strcmp (tag, label->tag)) - return label; - } - - return NULL; -} - - -static char * -tag_from_name (const char *name) -{ - /* this does thunderbird, just do not ask */ - char *s1, *s2, *p; - const char *bads = " ()/{%*<>\\\""; - - if (!name || !*name) - return NULL; - - s1 = g_strdup (name); - for (p = s1; p && *p; p++) { - if (strchr (bads, *p)) - *p = '_'; - } - - s2 = camel_utf8_utf7 (s1); - g_free (s1); - - s1 = g_ascii_strdown (s2, -1); - g_free (s2); - - return s1; -} - -/** - * e_util_labels_add - * Creates new label at the end of actual list of labels. - * - * @param name User readable name of this label. Should not be NULL. - * @param color Color assigned to this label. Should not be NULL. - * @return If succeeded then new label tag, NULL otherwise. - * Returned pointer should be freed with g_free. - * It will return NULL when the tag will be same as already existed. - * Tag name is generated in similar way as in Thunderbird. - **/ -char * -e_util_labels_add (const char *name, const GdkColor *color) -{ - EUtilLabel *label; - GSList *labels; - char *tag; - - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (color != NULL, NULL); - - labels = e_util_labels_parse (NULL); - tag = tag_from_name (name); - - if (!tag || find_label (labels, tag) != NULL) { - g_free (tag); - e_util_labels_free (labels); - return NULL; - } - - label = g_new0 (EUtilLabel, 1); - label->tag = g_strdup (tag); - label->name = g_strdup (name); - label->colour = gdk_color_to_string (color); - - labels = g_slist_append (labels, label); - - flush_labels_cache (labels, TRUE); - - return tag; -} - -/** - * e_util_labels_add_with_dlg - * This will open a dialog to add or edit label. - * - * @param parent Parent widget for the dialog. - * @param tag A tag for existing label to edit or NULL to add new label. - * @return Tag for newly added label or NULL, if something failed. - * Returned value should be freed with g_free. - **/ -char * -e_util_labels_add_with_dlg (GtkWindow *parent, const char *tag) -{ - GtkWidget *table, *dialog, *l, *e, *c; - const char *name; - GdkColor color; - gboolean is_edit = FALSE; - char *new_tag = NULL; - GSList *labels; - - table = gtk_table_new (2, 2, FALSE); - - labels = e_util_labels_parse (NULL); - name = tag ? e_util_labels_get_name (labels, tag) : NULL; - - l = gtk_label_new_with_mnemonic (_("Label _Name:")); - e = gtk_entry_new (); - c = gtk_color_button_new (); - - if (!tag || !e_util_labels_get_color (labels, tag, &color)) - memset (&color, 0xCD, sizeof (GdkColor)); - else - is_edit = TRUE; - - if (name) - gtk_entry_set_text (GTK_ENTRY (e), name); - - gtk_entry_set_activates_default (GTK_ENTRY (e), TRUE); - gtk_label_set_mnemonic_widget (GTK_LABEL (l), e); - gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.0); - gtk_color_button_set_color (GTK_COLOR_BUTTON (c), &color); - - gtk_table_attach (GTK_TABLE (table), l, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); - gtk_table_attach (GTK_TABLE (table), e, 0, 1, 1, 2, 0, 0, 0, 0); - gtk_table_attach (GTK_TABLE (table), c, 1, 2, 1, 2, 0, 0, 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (table), 10); - gtk_widget_show_all (table); - - dialog = gtk_dialog_new_with_buttons (is_edit ? _("Edit Label") : _("Add Label"), - parent, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), table, TRUE, TRUE, 0); - - while (!new_tag) { - const char *error = NULL; - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - name = gtk_entry_get_text (GTK_ENTRY (e)); - gtk_color_button_get_color (GTK_COLOR_BUTTON (c), &color); - - if (!name || !*name) - error = _("Label name cannot be empty."); - else if (is_edit) { - e_util_labels_set_data (tag, name, &color); - break; - } else if (!(new_tag = e_util_labels_add (name, &color))) - error = _("A label having the same tag already exists on the server. Please rename your label."); - else - break; - } else - break; - - if (error) - e_notice (parent, GTK_MESSAGE_ERROR, error); - } - - gtk_widget_destroy (dialog); - e_util_labels_free (labels); - - return new_tag; -} - -/** - * e_util_labels_remove - * - * @param tag Tag of the label to remove. - * @return Whether was removed. - **/ -gboolean -e_util_labels_remove (const char *tag) -{ - EUtilLabel *label; - GSList *labels; - - g_return_val_if_fail (tag != NULL, FALSE); - - labels = e_util_labels_parse (NULL); - label = find_label (labels, tag); - - if (!label) { - e_util_labels_free (labels); - return FALSE; - } - - labels = g_slist_remove (labels, label); - - free_label_struct (label); - - return flush_labels_cache (labels, TRUE); -} - -/** - * e_util_labels_set_data - * - * @param tag Tag of the label of our interest. - * @param name New name for the label. - * @param color New color for the label. - * @return Whether successfully saved. - **/ -gboolean -e_util_labels_set_data (const char *tag, const char *name, const GdkColor *color) -{ - EUtilLabel *label; - GSList *labels; - - g_return_val_if_fail (tag != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - labels = e_util_labels_parse (NULL); - label = find_label (labels, tag); - - if (!label) { - e_util_labels_free (labels); - return FALSE; - } - - g_free (label->name); - label->name = g_strdup (name); - - g_free (label->colour); - label->colour = gdk_color_to_string (color); - - return flush_labels_cache (labels, TRUE); -} - -/** - * e_util_labels_is_system - * - * @return Whether the tag is one of default/system labels or not. - **/ -gboolean -e_util_labels_is_system (const char *tag) -{ - int i; - - if (!tag) - return FALSE; - - for (i = 0; i < LABEL_DEFAULTS_NUM; i++) { - if (strcmp (tag, label_defaults[i].tag) == 0) - return TRUE; - } - - return FALSE; -} - -/** - * e_util_labels_get_new_tag - * - * @param old_tag Tag of the label from old version of Evolution. - * @return New tag name equivalent with the old tag, or NULL if no such name existed before. - **/ -const char * -e_util_labels_get_new_tag (const char *old_tag) -{ - int i; - - if (!old_tag) - return NULL; - - for (i = 0; i < LABEL_DEFAULTS_NUM; i++) { - /* default labels have same name as those old, only with prefix "$Label" */ - if (!strcmp (old_tag, label_defaults[i].tag + 6)) - return label_defaults[i].tag; - } - - return NULL; -} - -/** - * e_util_labels_get_name - * - * @param labels Cache of labels from call of @ref e_util_labels_parse. - * The returned pointer will be taken from this list, so it's alive as long as the list. - * @param tag Tag of the label of our interest. - * @return Name of the label with that tag or NULL, if no such label exists. - **/ -const char * -e_util_labels_get_name (GSList *labels, const char *tag) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, NULL); - - label = find_label (labels, tag); - if (!label) - return NULL; - - return label->name; -} - -/** - * e_util_labels_get_color - * - * @param labels Cache of labels from call of @ref e_util_labels_parse. - * @param tag Tag of the label of our interest. - * @param color [out] Actual color of the label with that tag, or unchanged if failed. - * @return Whether found such label and color has been set. - **/ -gboolean -e_util_labels_get_color (GSList *labels, const char *tag, GdkColor *color) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - label = find_label (labels, tag); - if (!label) - return FALSE; - - return gdk_color_parse (label->colour, color); -} - -/** - * e_util_labels_get_color_str - * - * @param labels Cache of labels from call of @ref e_util_labels_parse. - * The returned pointer will be taken from this list, so it's alive as long as the list. - * @param tag Tag of the label of our interest. - * @return String representation of that label, or NULL, is no such label exists. - **/ -const char * -e_util_labels_get_color_str (GSList *labels, const char *tag) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, FALSE); - - label = find_label (labels, tag); - if (!label) - return FALSE; - - return label->colour; -} - -/** - * e_util_labels_get_filter_options: - * Returns list of newly allocated struct _filter_option-s, to be used in filters. - **/ -GSList * -e_util_labels_get_filter_options (void) -{ - GSList *known = e_util_labels_parse (NULL), *l; - GSList *res = NULL; - - for (l = known; l; l = l->next) { - EUtilLabel *label = l->data; - const char *tag; - struct _filter_option *fo; - - if (!label) - continue; - - tag = label->tag; - - if (tag && strncmp (tag, "$Label", 6) == 0) - tag += 6; - - fo = g_new0 (struct _filter_option, 1); - fo->title = e_str_without_underscores (label->name); - fo->value = g_strdup (tag); - - res = g_slist_prepend (res, fo); - } - - e_util_labels_free (known); - - return g_slist_reverse (res); -} diff --git a/e-util/e-util-labels.h b/e-util/e-util-labels.h deleted file mode 100644 index 26520ff226..0000000000 --- a/e-util/e-util-labels.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _E_UTIL_LABELS_H -#define _E_UTIL_LABELS_H - -#include <gtk/gtk.h> - -struct _GtkWindow; -struct _GConfClient; - -typedef struct { - char *tag; - char *name; - char *colour; -} EUtilLabel; - -#define E_UTIL_LABELS_GCONF_KEY "/apps/evolution/mail/labels" - -#define LABEL_DEFAULTS_NUM 5 -extern EUtilLabel label_defaults[LABEL_DEFAULTS_NUM]; - -GSList * e_util_labels_parse (struct _GConfClient *client); -void e_util_labels_free (GSList *labels); - -char * e_util_labels_add (const char *name, const GdkColor *color); -char * e_util_labels_add_with_dlg (struct _GtkWindow *parent, const char *tag); -gboolean e_util_labels_remove (const char *tag); -gboolean e_util_labels_set_data (const char *tag, const char *name, const GdkColor *color); - -gboolean e_util_labels_is_system (const char *tag); -const char *e_util_labels_get_new_tag (const char *old_tag); - -const char *e_util_labels_get_name (GSList *labels, const char *tag); -gboolean e_util_labels_get_color (GSList *labels, const char *tag, GdkColor *color); -const char *e_util_labels_get_color_str (GSList *labels, const char *tag); - -GSList * e_util_labels_get_filter_options (void); - -#endif /* _E_UTIL_LABELS_H */ diff --git a/e-util/e-util.c b/e-util/e-util.c index fc4f71f187..576f46e54b 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -521,6 +521,30 @@ e_write_file_uri (const gchar *filename, const gchar *data) return res; } +/** + * e_color_to_value: + * color: a #GdkColor + * + * Converts a #GdkColor to a 24-bit RGB color value. + * + * Returns: a 24-bit color value + **/ +guint32 +e_color_to_value (GdkColor *color) +{ + guint16 red; + guint16 green; + guint16 blue; + + g_return_val_if_fail (color != NULL, 0); + + red = color->red >> 8; + green = color->green >> 8; + blue = color->blue >> 8; + + return (guint32) (((red << 16) | (green << 8) | blue) & 0xffffff); +} + static gint epow10 (gint number) { @@ -1487,27 +1511,6 @@ e_util_read_file (const char *filename, gboolean filename_is_uri, char **buffer, return res; } -GSList * -e_util_get_category_filter_options (void) -{ - GSList *res = NULL; - GList *clist, *l; - - clist = e_categories_get_list (); - for (l = clist; l; l = l->next) { - const char *cname = l->data; - struct _filter_option *fo = g_new0 (struct _filter_option, 1); - - fo->title = g_strdup (cname); - fo->value = g_strdup (cname); - res = g_slist_prepend (res, fo); - } - - g_list_free (clist); - - return g_slist_reverse (res); -} - static gpointer e_camel_object_copy (gpointer camel_object) { diff --git a/e-util/e-util.h b/e-util/e-util.h index 480da24eac..c748aaed8e 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -69,6 +69,7 @@ gint e_int_compare (gconstpointer x, gconstpointer y); gboolean e_write_file_uri (const gchar *filename, const gchar *data); +guint32 e_color_to_value (GdkColor *color); /* This only makes a filename safe for usage as a filename. * It still may have shell meta-characters in it. */ @@ -129,7 +130,8 @@ gboolean e_file_lock_create (void); void e_file_lock_destroy (void); gboolean e_file_lock_exists (void); -gchar * e_util_guess_mime_type (const gchar *filename, gboolean localfile); +gchar * e_util_guess_mime_type (const gchar *filename, + gboolean localfile); gchar * e_util_filename_to_uri (const gchar *filename); gchar * e_util_uri_to_filename (const gchar *uri); @@ -139,7 +141,15 @@ gboolean e_util_read_file (const gchar *filename, gsize *read, GError **error); -GSList *e_util_get_category_filter_options (void); +/* Camel uses its own object system, so we have to box + * CamelObjects to safely use them as GObject properties. */ +#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ()) +GType e_camel_object_get_type (void); + +/* Camel uses its own object system, so we have to box + * CamelObjects to safely use them as GObject properties. */ +#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ()) +GType e_camel_object_get_type (void); /* Camel uses its own object system, so we have to box * CamelObjects to safely use them as GObject properties. */ diff --git a/e-util/gconf-bridge.c b/e-util/gconf-bridge.c index 81fe08ef14..852d5f8f53 100644 --- a/e-util/gconf-bridge.c +++ b/e-util/gconf-bridge.c @@ -1082,17 +1082,17 @@ gconf_bridge_bind_string_list_store (GConfBridge *bridge, (list_store_binding_store_changed_cb), binding); binding->row_changed_id = - g_signal_connect_swapped (list_store, "row-inserted", + g_signal_connect_swapped (list_store, "row-changed", G_CALLBACK (list_store_binding_store_changed_cb), binding); binding->row_deleted_id = - g_signal_connect_swapped (list_store, "row-inserted", + g_signal_connect_swapped (list_store, "row-deleted", G_CALLBACK (list_store_binding_store_changed_cb), binding); binding->rows_reordered_id = - g_signal_connect_swapped (list_store, "row-inserted", + g_signal_connect_swapped (list_store, "rows-reordered", G_CALLBACK (list_store_binding_store_changed_cb), binding); |