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 }