/* * 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 * * * Authors: * Michael Zucchi * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_IMPORT_H #include #endif #include #include #include #include "e-import.h" #include #define d(x) typedef struct _EImportImporters EImportImporters; struct _EImportImporters { EImportImporter *importer; EImportImporterFunc free; gpointer data; }; static gpointer parent_class; static void import_finalize (GObject *object) { EImport *import = E_IMPORT (object); g_free (import->id); /* Chain up to parent's finalize () method. */ G_OBJECT_CLASS (parent_class)->finalize (object); } static void import_target_free (EImport *import, EImportTarget *target) { switch (target->type) { case E_IMPORT_TARGET_URI: { EImportTargetURI *s = (EImportTargetURI *) target; g_free (s->uri_src); g_free (s->uri_dest); break; } default: break; } g_datalist_clear (&target->data); g_free (target); g_object_unref (import); } static void import_class_init (EImportClass *class) { GObjectClass *object_class; parent_class = g_type_class_peek_parent (class); object_class = G_OBJECT_CLASS (class); object_class->finalize = import_finalize; class->target_free = import_target_free; } /** * e_import_get_type: * * Standard GObject method. Used to subclass for the concrete * implementations. * * Return value: EImport type. **/ GType e_import_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo type_info = { sizeof (EImportClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) import_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (EImport), 0, /* n_preallocs */ (GInstanceInitFunc) NULL, NULL /* value_table */ }; type = g_type_register_static ( G_TYPE_OBJECT, "EImport", &type_info, 0); } return type; } /** * e_import_construct: * @ep: The instance to initialise. * @id: The name of the instance. * * Used by implementing classes to initialise base parameters. * * Return value: @ep is returned. **/ EImport *e_import_construct (EImport *ep, const gchar *id) { ep->id = g_strdup (id); return ep; } EImport * e_import_new (const gchar *id) { EImport *import; import = g_object_new (E_TYPE_IMPORT, NULL); return e_import_construct (import, id); } /** * e_import_import: * @import: an #EImport * @t: Target to import. * @im: Importer to use. * @status: Status callback, called with progress information. * @done: Complete callback, will always be called once complete. * @data: * * Run the import function of the selected importer. Once the * importer has finished, it MUST call the e_import_complete () * function. This allows importers to run in synchronous or * asynchronous mode. * * When complete, the @done callback will be called. **/ void e_import_import (EImport *import, EImportTarget *t, EImportImporter *im, EImportStatusFunc status, EImportCompleteFunc done, gpointer data) { g_return_if_fail (im != NULL); import->status = status; import->done = done; import->done_data = data; im->import (import, t, im); } void e_import_cancel (EImport *import, EImportTarget *t, EImportImporter *im) { if (im->cancel) im->cancel (import, t, im); } /** * e_import_get_widget: * @import: an #EImport * @target: Target of interest * @im: Importer to get widget of * * Gets a widget that the importer uses to configure its * destination. This widget should be packed into a container * widget. It should not be shown_all. * * Return value: NULL if the importer doesn't support/require * a destination. **/ GtkWidget * e_import_get_widget (EImport *import, EImportTarget *target, EImportImporter *im) { g_return_val_if_fail (im != NULL, NULL); g_return_val_if_fail (target != NULL, NULL); return im->get_widget (import, target, im); } /** * e_import_complete: * @import: an #EImport * @target: Target just completed (unused currently) * * Signify that an import is complete. This must be called by * importer implementations when they are done. **/ void e_import_complete (EImport *import, EImportTarget *target) { if (import->done) import->done (import, import->done_data); } void e_import_status (EImport *import, EImportTarget *target, const gchar *what, gint pc) { if (import->status) import->status (import, what, pc, import->done_data); } /** * e_import_get_importers: * @emp: * @target: * * Get a list of importers. If @target is supplied, then only * importers which support the type and location specified by the * target are listed. If @target is NULL, then all importers are * listed. * * Return value: A list of importers. The list should be freed when * no longer needed. **/ GSList * e_import_get_importers (EImport *emp, EImportTarget *target) { GSList *importers = NULL; GList *link; link = E_IMPORT_GET_CLASS (emp)->importers; while (link != NULL) { EImportImporters *ei = link->data; if (target == NULL || (ei->importer->type == target->type && ei->importer->supported (emp, target, ei->importer))) { importers = g_slist_append (importers, ei->importer); } link = g_list_next (link); } return importers; } /* ********************************************************************** */ static gint importer_compare (EImportImporters *node_a, EImportImporters *node_b) { gint pri_a = node_a->importer->pri; gint pri_b = node_b->importer->pri; return (pri_a == pri_b) ? 0 : (pri_a < pri_b) ? -1 : 1; } /** * e_import_class_add_importer: * @ec: An initialised implementing instance of EImport. * @importer: Importer to add. * @freefunc: If supplied, called to free the importer node * when it is no longer needed. * @data: Data for the callback. * **/ void e_import_class_add_importer (EImportClass *class, EImportImporter *importer, EImportImporterFunc freefunc, gpointer data) { EImportImporters *node; node = g_malloc (sizeof (*node)); node->importer = importer; node->free = freefunc; node->data = data; class->importers = g_list_sort ( g_list_prepend (class->importers, node), (GCompareFunc) importer_compare); } /** * e_import_target_new: * @ep: Parent EImport object. * @type: type, up to implementor * @size: Size of object to allocate. * * Allocate a new import target suitable for this class. Implementing * classes will define the actual content of the target. **/ gpointer e_import_target_new (EImport *ep, gint type, gsize size) { EImportTarget *t; if (size < sizeof (EImportTarget)) { g_warning ("Size less than size of EImportTarget\n"); size = sizeof (EImportTarget); } t = g_malloc0 (size); t->import = ep; g_object_ref (ep); t->type = type; g_datalist_init (&t->data); return t; } /** * e_import_target_free: * @ep: Parent EImport object. * @o: The target to fre. * * Free a target. The implementing class can override this method to * free custom targets. **/ void e_import_target_free (EImport *ep, gpointer o) { EImportTarget *t = o; ((EImportClass *)G_OBJECT_GET_CLASS (ep))->target_free (ep, t); } EImportTargetURI * e_import_target_new_uri (EImport *import, const gchar *uri_src, const gchar *uri_dst) { EImportTargetURI *t = e_import_target_new (import, E_IMPORT_TARGET_URI, sizeof (*t)); t->uri_src = g_strdup (uri_src); t->uri_dest = g_strdup (uri_dst); return t; } EImportTargetHome * e_import_target_new_home (EImport *import) { return e_import_target_new ( import, E_IMPORT_TARGET_HOME, sizeof (EImportTargetHome)); } /* ********************************************************************** */ /* Import menu plugin handler */ /* */ static gpointer emph_parent_class; #define emph ((EImportHook *)eph) static const EImportHookTargetMask eih_no_masks[] = { { NULL } }; static const EImportHookTargetMap eih_targets[] = { { "uri", E_IMPORT_TARGET_URI, eih_no_masks }, { "home", E_IMPORT_TARGET_HOME, eih_no_masks }, { NULL } }; static gboolean eih_supported (EImport *ei, EImportTarget *target, EImportImporter *im) { struct _EImportHookImporter *ihook = (EImportHookImporter *)im; EImportHook *hook = im->user_data; return e_plugin_invoke (hook->hook.plugin, ihook->supported, target) != NULL; } static GtkWidget * eih_get_widget (EImport *ei, EImportTarget *target, EImportImporter *im) { struct _EImportHookImporter *ihook = (EImportHookImporter *)im; EImportHook *hook = im->user_data; return e_plugin_invoke (hook->hook.plugin, ihook->get_widget, target); } static void eih_import (EImport *ei, EImportTarget *target, EImportImporter *im) { struct _EImportHookImporter *ihook = (EImportHookImporter *)im; EImportHook *hook = im->user_data; e_plugin_invoke (hook->hook.plugin, ihook->import, target); } static void eih_cancel (EImport *ei, EImportTarget *target, EImportImporter *im) { struct _EImportHookImporter *ihook = (EImportHookImporter *)im; EImportHook *hook = im->user_data; e_plugin_invoke (hook->hook.plugin, ihook->cancel, target); } static void eih_free_importer (EImportImporter *im, gpointer data) { EImportHookImporter *ihook = (EImportHookImporter *)im; g_free (ihook->supported); g_free (ihook->get_widget); g_free (ihook->import); g_free (ihook); } static struct _EImportHookImporter * emph_construct_importer (EPluginHook *eph, xmlNodePtr root) { struct _EImportHookImporter *item; EImportHookTargetMap *map; EImportHookClass *class = (EImportHookClass *)G_OBJECT_GET_CLASS (eph); gchar *tmp; d (printf (" loading import item\n")); item = g_malloc0 (sizeof (*item)); tmp = (gchar *)xmlGetProp (root, (const guchar *)"target"); if (tmp == NULL) goto error; map = g_hash_table_lookup (class->target_map, tmp); xmlFree (tmp); if (map == NULL) goto error; item->importer.type = map->id; item->supported = e_plugin_xml_prop (root, "supported"); item->get_widget = e_plugin_xml_prop (root, "get-widget"); item->import = e_plugin_xml_prop (root, "import"); item->cancel = e_plugin_xml_prop (root, "cancel"); item->importer.name = e_plugin_xml_prop (root, "name"); item->importer.description = e_plugin_xml_prop (root, "description"); item->importer.user_data = eph; if (item->import == NULL || item->supported == NULL) goto error; item->importer.supported = eih_supported; item->importer.import = eih_import; if (item->get_widget) item->importer.get_widget = eih_get_widget; if (item->cancel) item->importer.cancel = eih_cancel; return item; error: d (printf ("error!\n")); eih_free_importer ((EImportImporter *)item, NULL); return NULL; } static gint emph_construct (EPluginHook *eph, EPlugin *ep, xmlNodePtr root) { xmlNodePtr node; EImportClass *class; d (printf ("loading import hook\n")); if (E_PLUGIN_HOOK_CLASS (emph_parent_class)->construct (eph, ep, root) == -1) return -1; class = E_IMPORT_HOOK_GET_CLASS (eph)->import_class; node = root->children; while (node) { if (strcmp ((gchar *)node->name, "importer") == 0) { struct _EImportHookImporter *ihook; ihook = emph_construct_importer (eph, node); if (ihook) { e_import_class_add_importer (class, &ihook->importer, eih_free_importer, eph); emph->importers = g_slist_append (emph->importers, ihook); } } node = node->next; } eph->plugin = ep; return 0; } static void emph_class_init (EImportHookClass *class) { EPluginHookClass *plugin_hook_class; gint ii; plugin_hook_class = E_PLUGIN_HOOK_CLASS (class); plugin_hook_class->id = "org.gnome.evolution.import:1.0"; plugin_hook_class->construct = emph_construct; /** @HookClass: Evolution Importers * @Id: org.gnome.evolution.import:1.0 * @Target: EImportTarget * * A hook for data importers. **/ class->target_map = g_hash_table_new (g_str_hash, g_str_equal); class->import_class = g_type_class_ref (E_TYPE_IMPORT); for (ii = 0; eih_targets[ii].type; ii++) e_import_hook_class_add_target_map (class, &eih_targets[ii]); } GType e_import_hook_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GTypeInfo type_info = { sizeof (EImportHookClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) emph_class_init, (GClassFinalizeFunc) NULL, NULL, /* class_data */ sizeof (EImportHook), 0, /* n_preallocs */ (GInstanceInitFunc) NULL, NULL /* value_table */ }; emph_parent_class = g_type_class_ref (e_plugin_hook_get_type ()); type = g_type_register_static ( E_TYPE_PLUGIN_HOOK, "EImportHook", &type_info, 0); } return type; } /** * e_import_hook_class_add_target_map: * * @class: The dervied EimportHook class. * @map: A map used to describe a single EImportTarget type for this * class. * * Add a targe tmap to a concrete derived class of EImport. The * target map enumates the target types available for the implenting * class. **/ void e_import_hook_class_add_target_map (EImportHookClass *class, const EImportHookTargetMap *map) { g_hash_table_insert ( class->target_map, (gpointer) map->type, (gpointer) map); }