evolution-3.6.4/e-util/e-import.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Michael Zucchi <notzed@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #ifdef HAVE_CONFIG_H
 24 #include <config.h>
 25 #endif
 26 
 27 #ifdef HAVE_IMPORT_H
 28 #include <import.h>
 29 #endif
 30 
 31 #include <string.h>
 32 #include <stdlib.h>
 33 
 34 #include <gtk/gtk.h>
 35 
 36 #include "e-import.h"
 37 
 38 #include <glib/gi18n.h>
 39 
 40 #define d(x)
 41 
 42 typedef struct _EImportImporters EImportImporters;
 43 
 44 struct _EImportImporters {
 45 	EImportImporter *importer;
 46 	EImportImporterFunc free;
 47 	gpointer data;
 48 };
 49 
 50 G_DEFINE_TYPE (
 51 	EImport,
 52 	e_import,
 53 	G_TYPE_OBJECT)
 54 
 55 static void
 56 import_finalize (GObject *object)
 57 {
 58 	EImport *import = E_IMPORT (object);
 59 
 60 	g_free (import->id);
 61 
 62 	/* Chain up to parent's finalize () method. */
 63 	G_OBJECT_CLASS (e_import_parent_class)->finalize (object);
 64 }
 65 
 66 static void
 67 import_target_free (EImport *import,
 68                     EImportTarget *target)
 69 {
 70 	switch (target->type) {
 71 	case E_IMPORT_TARGET_URI: {
 72 		EImportTargetURI *s = (EImportTargetURI *) target;
 73 
 74 		g_free (s->uri_src);
 75 		g_free (s->uri_dest);
 76 		break; }
 77 	default:
 78 		break;
 79 	}
 80 
 81 	g_datalist_clear (&target->data);
 82 	g_free (target);
 83 	g_object_unref (import);
 84 }
 85 
 86 static void
 87 e_import_class_init (EImportClass *class)
 88 {
 89 	GObjectClass *object_class;
 90 
 91 	object_class = G_OBJECT_CLASS (class);
 92 	object_class->finalize = import_finalize;
 93 
 94 	class->target_free = import_target_free;
 95 }
 96 
 97 static void
 98 e_import_init (EImport *import)
 99 {
100 }
101 
102 /**
103  * e_import_construct:
104  * @ep: The instance to initialise.
105  * @id: The name of the instance.
106  *
107  * Used by implementing classes to initialise base parameters.
108  *
109  * Return value: @ep is returned.
110  **/
111 EImport *e_import_construct (EImport *ep, const gchar *id)
112 {
113 	ep->id = g_strdup (id);
114 
115 	return ep;
116 }
117 
118 EImport *
119 e_import_new (const gchar *id)
120 {
121 	EImport *import;
122 
123 	import = g_object_new (E_TYPE_IMPORT, NULL);
124 
125 	return e_import_construct (import, id);
126 }
127 
128 /**
129  * e_import_import:
130  * @import: an #EImport
131  * @t: Target to import.
132  * @im: Importer to use.
133  * @status: Status callback, called with progress information.
134  * @done: Complete callback, will always be called once complete.
135  * @data: user data for callback functions
136  *
137  * Run the import function of the selected importer.  Once the
138  * importer has finished, it MUST call the e_import_complete ()
139  * function.  This allows importers to run in synchronous or
140  * asynchronous mode.
141  *
142  * When complete, the @done callback will be called.
143  **/
144 void
145 e_import_import (EImport *import,
146                  EImportTarget *t,
147                  EImportImporter *im,
148                  EImportStatusFunc status,
149                  EImportCompleteFunc done,
150                  gpointer data)
151 {
152 	g_return_if_fail (im != NULL);
153 
154 	import->status = status;
155 	import->done = done;
156 	import->done_data = data;
157 
158 	im->import (import, t, im);
159 }
160 
161 void
162 e_import_cancel (EImport *import,
163                  EImportTarget *t,
164                  EImportImporter *im)
165 {
166 	if (im->cancel)
167 		im->cancel (import, t, im);
168 }
169 
170 /**
171  * e_import_get_widget:
172  * @import: an #EImport
173  * @target: Target of interest
174  * @im: Importer to get widget of
175  *
176  * Gets a widget that the importer uses to configure its
177  * destination.  This widget should be packed into a container
178  * widget.  It should not be shown_all.
179  *
180  * Return value: NULL if the importer doesn't support/require
181  * a destination.
182  **/
183 GtkWidget *
184 e_import_get_widget (EImport *import,
185                      EImportTarget *target,
186                      EImportImporter *im)
187 {
188 	g_return_val_if_fail (im != NULL, NULL);
189 	g_return_val_if_fail (target != NULL, NULL);
190 
191 	return im->get_widget (import, target, im);
192 }
193 
194 /**
195  * e_import_get_preview_widget:
196  * @import: an #EImport
197  * @target: Target of interest
198  * @im: Importer to get a preview widget of
199  *
200  * Gets a widget that the importer uses to preview data to be
201  * imported.  This widget should be packed into a container
202  * widget.  It should not be shown_all.
203  *
204  * Return value: NULL if the importer doesn't support preview.
205  **/
206 GtkWidget *
207 e_import_get_preview_widget (EImport *import,
208                      EImportTarget *target,
209                      EImportImporter *im)
210 {
211 	g_return_val_if_fail (im != NULL, NULL);
212 	g_return_val_if_fail (target != NULL, NULL);
213 
214 	if (!im->get_preview)
215 		return NULL;
216 
217 	return im->get_preview (import, target, im);
218 }
219 
220 /**
221  * e_import_complete:
222  * @import: an #EImport
223  * @target: Target just completed (unused currently)
224  *
225  * Signify that an import is complete.  This must be called by
226  * importer implementations when they are done.
227  **/
228 void
229 e_import_complete (EImport *import,
230                    EImportTarget *target)
231 {
232 	if (import->done)
233 		import->done (import, import->done_data);
234 }
235 
236 void
237 e_import_status (EImport *import,
238                  EImportTarget *target,
239                  const gchar *what,
240                  gint pc)
241 {
242 	if (import->status)
243 		import->status (import, what, pc, import->done_data);
244 }
245 
246 /**
247  * e_import_get_importers:
248  * @emp: an #EImport
249  * @target: an #EImportTarget
250  *
251  * Get a list of importers.  If @target is supplied, then only
252  * importers which support the type and location specified by the
253  * target are listed.  If @target is NULL, then all importers are
254  * listed.
255  *
256  * Return value: A list of importers.  The list should be freed when
257  * no longer needed.
258  **/
259 GSList *
260 e_import_get_importers (EImport *emp,
261                         EImportTarget *target)
262 {
263 	GSList *importers = NULL;
264 	GList *link;
265 
266 	link = E_IMPORT_GET_CLASS (emp)->importers;
267 
268 	while (link != NULL) {
269 		EImportImporters *ei = link->data;
270 
271 		if (target == NULL
272 		    || (ei->importer->type == target->type
273 			&& ei->importer->supported (emp, target, ei->importer))) {
274 			importers = g_slist_append (importers, ei->importer);
275 		}
276 
277 		link = g_list_next (link);
278 	}
279 
280 	return importers;
281 }
282 
283 /* ********************************************************************** */
284 
285 static gint
286 importer_compare (EImportImporters *node_a,
287                   EImportImporters *node_b)
288 {
289 	gint pri_a = node_a->importer->pri;
290 	gint pri_b = node_b->importer->pri;
291 
292 	return (pri_a == pri_b) ? 0 : (pri_a < pri_b) ? -1 : 1;
293 }
294 
295 /**
296  * e_import_class_add_importer:
297  * @ec: An initialised implementing instance of EImport.
298  * @importer: Importer to add.
299  * @freefunc: If supplied, called to free the importer node
300  * when it is no longer needed.
301  * @data: Data for the callback.
302  *
303  **/
304 void
305 e_import_class_add_importer (EImportClass *class,
306                              EImportImporter *importer,
307                              EImportImporterFunc freefunc,
308                              gpointer data)
309 {
310 	EImportImporters *node;
311 
312 	node = g_malloc (sizeof (*node));
313 	node->importer = importer;
314 	node->free = freefunc;
315 	node->data = data;
316 
317 	class->importers = g_list_sort (
318 		g_list_prepend (class->importers, node),
319 		(GCompareFunc) importer_compare);
320 }
321 
322 /**
323  * e_import_target_new:
324  * @ep: Parent EImport object.
325  * @type: type, up to implementor
326  * @size: Size of object to allocate.
327  *
328  * Allocate a new import target suitable for this class.  Implementing
329  * classes will define the actual content of the target.
330  **/
331 gpointer
332 e_import_target_new (EImport *ep,
333                      gint type,
334                      gsize size)
335 {
336 	EImportTarget *t;
337 
338 	if (size < sizeof (EImportTarget)) {
339 		g_warning ("Size less than size of EImportTarget\n");
340 		size = sizeof (EImportTarget);
341 	}
342 
343 	t = g_malloc0 (size);
344 	t->import = ep;
345 	g_object_ref (ep);
346 	t->type = type;
347 	g_datalist_init (&t->data);
348 
349 	return t;
350 }
351 
352 /**
353  * e_import_target_free:
354  * @ep: Parent EImport object.
355  * @o: The target to fre.
356  *
357  * Free a target.  The implementing class can override this method to
358  * free custom targets.
359  **/
360 void
361 e_import_target_free (EImport *ep,
362                       gpointer o)
363 {
364 	EImportTarget *t = o;
365 
366 	((EImportClass *) G_OBJECT_GET_CLASS (ep))->target_free (ep, t);
367 }
368 
369 EImportTargetURI *
370 e_import_target_new_uri (EImport *import,
371                          const gchar *uri_src,
372                          const gchar *uri_dst)
373 {
374 	EImportTargetURI *t;
375 
376 	t = e_import_target_new (import, E_IMPORT_TARGET_URI, sizeof (*t));
377 	t->uri_src = g_strdup (uri_src);
378 	t->uri_dest = g_strdup (uri_dst);
379 
380 	return t;
381 }
382 
383 EImportTargetHome *
384 e_import_target_new_home (EImport *import)
385 {
386 	return e_import_target_new (
387 		import, E_IMPORT_TARGET_HOME, sizeof (EImportTargetHome));
388 }
389 
390 /* ********************************************************************** */
391 
392 /* Import menu plugin handler */
393 
394 /*
395  * <e-plugin
396  *   class="org.gnome.mail.plugin.import:1.0"
397  *   id="org.gnome.mail.plugin.import.item:1.0"
398  *   type="shlib"
399  *   location="/opt/gnome2/lib/camel/1.0/libcamelimap.so"
400  *   name="imap"
401  *   description="IMAP4 and IMAP4v1 mail store">
402  *   <hook class="org.gnome.mail.importMenu:1.0"
403  *         handler="HandleImport">
404  *   <menu id="any" target="select">
405  *    <item
406  *     type="item|toggle|radio|image|submenu|bar"
407  *     active
408  *     path="foo/bar"
409  *     label="label"
410  *     icon="foo"
411  *     activate="ep_view_emacs"/>
412  *   </menu>
413  * </e-plugin>
414  */
415 
416 #define emph ((EImportHook *)eph)
417 
418 static const EImportHookTargetMask eih_no_masks[] = {
419 	{ NULL }
420 };
421 
422 static const EImportHookTargetMap eih_targets[] = {
423 	{ "uri", E_IMPORT_TARGET_URI, eih_no_masks },
424 	{ "home", E_IMPORT_TARGET_HOME, eih_no_masks },
425 	{ NULL }
426 };
427 
428 G_DEFINE_TYPE (
429 	EImportHook,
430 	e_import_hook,
431 	E_TYPE_PLUGIN_HOOK)
432 
433 static gboolean
434 eih_supported (EImport *ei,
435                EImportTarget *target,
436                EImportImporter *im)
437 {
438 	struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
439 	EImportHook *hook = im->user_data;
440 
441 	return e_plugin_invoke (hook->hook.plugin, ihook->supported, target) != NULL;
442 }
443 
444 static GtkWidget *
445 eih_get_widget (EImport *ei,
446                 EImportTarget *target,
447                 EImportImporter *im)
448 {
449 	struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
450 	EImportHook *hook = im->user_data;
451 
452 	return e_plugin_invoke (hook->hook.plugin, ihook->get_widget, target);
453 }
454 
455 static void
456 eih_import (EImport *ei,
457             EImportTarget *target,
458             EImportImporter *im)
459 {
460 	struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
461 	EImportHook *hook = im->user_data;
462 
463 	e_plugin_invoke (hook->hook.plugin, ihook->import, target);
464 }
465 
466 static void
467 eih_cancel (EImport *ei,
468             EImportTarget *target,
469             EImportImporter *im)
470 {
471 	struct _EImportHookImporter *ihook = (EImportHookImporter *) im;
472 	EImportHook *hook = im->user_data;
473 
474 	e_plugin_invoke (hook->hook.plugin, ihook->cancel, target);
475 }
476 
477 static void
478 eih_free_importer (EImportImporter *im,
479                    gpointer data)
480 {
481 	EImportHookImporter *ihook = (EImportHookImporter *) im;
482 
483 	g_free (ihook->supported);
484 	g_free (ihook->get_widget);
485 	g_free (ihook->import);
486 	g_free (ihook);
487 }
488 
489 static struct _EImportHookImporter *
490 emph_construct_importer (EPluginHook *eph,
491                          xmlNodePtr root)
492 {
493 	struct _EImportHookImporter *item;
494 	EImportHookTargetMap *map;
495 	EImportHookClass *class = (EImportHookClass *) G_OBJECT_GET_CLASS (eph);
496 	gchar *tmp;
497 
498 	d (printf ("  loading import item\n"));
499 	item = g_malloc0 (sizeof (*item));
500 
501 	tmp = (gchar *) xmlGetProp (root, (const guchar *)"target");
502 	if (tmp == NULL)
503 		goto error;
504 	map = g_hash_table_lookup (class->target_map, tmp);
505 	xmlFree (tmp);
506 	if (map == NULL)
507 		goto error;
508 
509 	item->importer.type = map->id;
510 	item->supported = e_plugin_xml_prop (root, "supported");
511 	item->get_widget = e_plugin_xml_prop (root, "get-widget");
512 	item->import = e_plugin_xml_prop (root, "import");
513 	item->cancel = e_plugin_xml_prop (root, "cancel");
514 
515 	item->importer.name = e_plugin_xml_prop (root, "name");
516 	item->importer.description = e_plugin_xml_prop (root, "description");
517 
518 	item->importer.user_data = eph;
519 
520 	if (item->import == NULL || item->supported == NULL)
521 		goto error;
522 
523 	item->importer.supported = eih_supported;
524 	item->importer.import = eih_import;
525 	if (item->get_widget)
526 		item->importer.get_widget = eih_get_widget;
527 	if (item->cancel)
528 		item->importer.cancel = eih_cancel;
529 
530 	return item;
531 error:
532 	d (printf ("error!\n"));
533 	eih_free_importer ((EImportImporter *) item, NULL);
534 	return NULL;
535 }
536 
537 static gint
538 emph_construct (EPluginHook *eph,
539                 EPlugin *ep,
540                 xmlNodePtr root)
541 {
542 	xmlNodePtr node;
543 	EImportClass *class;
544 
545 	d (printf ("loading import hook\n"));
546 
547 	if (E_PLUGIN_HOOK_CLASS (e_import_hook_parent_class)->
548 		construct (eph, ep, root) == -1)
549 		return -1;
550 
551 	class = E_IMPORT_HOOK_GET_CLASS (eph)->import_class;
552 
553 	node = root->children;
554 	while (node) {
555 		if (strcmp ((gchar *) node->name, "importer") == 0) {
556 			struct _EImportHookImporter *ihook;
557 
558 			ihook = emph_construct_importer (eph, node);
559 			if (ihook) {
560 				e_import_class_add_importer (
561 					class, &ihook->importer,
562 					eih_free_importer, eph);
563 				emph->importers = g_slist_append (
564 					emph->importers, ihook);
565 			}
566 		}
567 		node = node->next;
568 	}
569 
570 	eph->plugin = ep;
571 
572 	return 0;
573 }
574 
575 static void
576 e_import_hook_class_init (EImportHookClass *class)
577 {
578 	EPluginHookClass *plugin_hook_class;
579 	gint ii;
580 
581 	plugin_hook_class = E_PLUGIN_HOOK_CLASS (class);
582 	plugin_hook_class->id = "org.gnome.evolution.import:1.0";
583 	plugin_hook_class->construct = emph_construct;
584 
585 	/** @HookClass: Evolution Importers
586 	 * @Id: org.gnome.evolution.import:1.0
587 	 * @Target: EImportTarget
588 	 *
589 	 * A hook for data importers.
590 	 **/
591 
592 	class->target_map = g_hash_table_new (g_str_hash, g_str_equal);
593 	class->import_class = g_type_class_ref (E_TYPE_IMPORT);
594 
595 	for (ii = 0; eih_targets[ii].type; ii++)
596 		e_import_hook_class_add_target_map (class, &eih_targets[ii]);
597 }
598 
599 static void
600 e_import_hook_init (EImportHook *hook)
601 {
602 }
603 
604 /**
605  * e_import_hook_class_add_target_map:
606  *
607  * @class: The dervied EimportHook class.
608  * @map: A map used to describe a single EImportTarget type for this
609  * class.
610  *
611  * Add a targe tmap to a concrete derived class of EImport.  The
612  * target map enumates the target types available for the implenting
613  * class.
614  **/
615 void
616 e_import_hook_class_add_target_map (EImportHookClass *class,
617                                     const EImportHookTargetMap *map)
618 {
619 	g_hash_table_insert (
620 		class->target_map, (gpointer) map->type, (gpointer) map);
621 }