1 /*
2 * go-plugin-service.c: Plugin services - reading XML info, activating, etc.
3 * (everything independent of plugin loading method)
4 *
5 * Author: Zbigniew Chyla (cyba@gnome.pl)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) version 3.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA.
21 */
22
23 #include <goffice/goffice-config.h>
24 #include "go-plugin-service.h"
25 #include "go-plugin-service-impl.h"
26
27 #include <goffice/app/error-info.h>
28 #include <goffice/app/go-plugin.h>
29 #include <goffice/app/file.h>
30 #include <goffice/app/file-priv.h>
31 #include <goffice/app/io-context.h>
32 #include <goffice/utils/go-glib-extras.h>
33 #include <goffice/utils/go-libxml-extras.h>
34
35 #include <gsf/gsf-input.h>
36 #include <gsf/gsf-output.h>
37 #include <libxml/globals.h>
38 #include <gsf/gsf-impl-utils.h>
39 #include <gsf/gsf-utils.h>
40 #include <glib/gi18n-lib.h>
41
42 #include <string.h>
43
44 /**
45 * GOPluginServiceFileOpenerCallbacks:
46 * @plugin_func_file_probe: probes the file, may be %NULL.
47 * @plugin_func_file_open: opens and reads the file.
48 **/
49
50 /**
51 * GOPluginServiceFileSaverCallbacks:
52 * @plugin_func_file_save: saves the file.
53 **/
54
55 /**
56 * GOPluginServiceGeneralCallbacks:
57 * @plugin_func_init: initializes the service.
58 * @plugin_func_cleanup: service cleanup.
59 **/
60
61 /**
62 * GOPluginServicePluginLoaderCallbacks:
63 * @plugin_func_get_loader_type: returns a #GType for a function loader.
64 * Used by gnumeric in the Python and Perl plugins.
65 **/
66
67 /**
68 * GOPluginServiceClass:
69 * @g_object_class: base class.
70 * @read_xml: read XML node containing the service description.
71 * @activate: actviates the service.
72 * @deactivate: deactivates the service.
73 * @get_description: gets the service description.
74 **/
75
76 /**
77 * GOPluginServiceGObjectLoaderClass:
78 * @plugin_service_class: parent class.
79 * @pending: has service instances by type names.
80 **/
81
82 #define CXML2C(s) ((char const *)(s))
83 #define CC2XML(s) ((xmlChar const *)(s))
84
85 static char *
xml2c(xmlChar * src)86 xml2c (xmlChar *src)
87 {
88 char *dst = g_strdup (CXML2C (src));
89 xmlFree (src);
90 return dst;
91 }
92
93 static GHashTable *services = NULL;
94
95 static GHashTable *
get_plugin_file_savers_hash(GOPlugin * plugin)96 get_plugin_file_savers_hash (GOPlugin *plugin)
97 {
98 GHashTable *hash;
99
100 hash = g_object_get_data (G_OBJECT (plugin), "file_savers_hash");
101 if (hash == NULL) {
102 hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
103 g_object_set_data_full (
104 G_OBJECT (plugin), "file_savers_hash",
105 hash, (GDestroyNotify) g_hash_table_destroy);
106 }
107
108 return hash;
109 }
110
111
112 static void
go_plugin_service_init(GObject * obj)113 go_plugin_service_init (GObject *obj)
114 {
115 GOPluginService *service = GO_PLUGIN_SERVICE (obj);
116
117 service->id = NULL;
118 service->is_active = FALSE;
119 service->is_loaded = FALSE;
120 service->plugin = NULL;
121 service->cbs_ptr = NULL;
122 service->saved_description = NULL;
123 }
124
125 static void
go_plugin_service_finalize(GObject * obj)126 go_plugin_service_finalize (GObject *obj)
127 {
128 GOPluginService *service = GO_PLUGIN_SERVICE (obj);
129 GObjectClass *parent_class;
130
131 g_free (service->id);
132 service->id = NULL;
133 g_free (service->saved_description);
134 service->saved_description = NULL;
135
136 parent_class = g_type_class_peek (G_TYPE_OBJECT);
137 parent_class->finalize (obj);
138 }
139
140 static void
go_plugin_service_class_init(GObjectClass * gobject_class)141 go_plugin_service_class_init (GObjectClass *gobject_class)
142 {
143 GOPluginServiceClass *plugin_service_class = GO_PLUGIN_SERVICE_CLASS (gobject_class);
144
145 gobject_class->finalize = go_plugin_service_finalize;
146 plugin_service_class->read_xml = NULL;
147 plugin_service_class->activate = NULL;
148 plugin_service_class->deactivate = NULL;
149 plugin_service_class->get_description = NULL;
150 }
151
152 GSF_CLASS (GOPluginService, go_plugin_service,
153 go_plugin_service_class_init, go_plugin_service_init,
154 G_TYPE_OBJECT)
155
156
157 /****************************************************************************/
158
159 /*
160 * GOPluginServiceGeneral
161 */
162
163 typedef struct{
164 GOPluginServiceClass plugin_service_class;
165 } GOPluginServiceGeneralClass;
166
167 struct _GOPluginServiceGeneral {
168 GOPluginService plugin_service;
169 GOPluginServiceGeneralCallbacks cbs;
170 };
171
172
173 static void
go_plugin_service_general_init(GObject * obj)174 go_plugin_service_general_init (GObject *obj)
175 {
176 GOPluginServiceGeneral *service_general = GO_PLUGIN_SERVICE_GENERAL (obj);
177
178 GO_PLUGIN_SERVICE (obj)->cbs_ptr = &service_general->cbs;
179 service_general->cbs.plugin_func_init = NULL;
180 service_general->cbs.plugin_func_cleanup = NULL;
181 }
182
183 static void
go_plugin_service_general_activate(GOPluginService * service,GOErrorInfo ** ret_error)184 go_plugin_service_general_activate (GOPluginService *service, GOErrorInfo **ret_error)
185 {
186 GOPluginServiceGeneral *service_general = GO_PLUGIN_SERVICE_GENERAL (service);
187 GOErrorInfo *error = NULL;
188
189 GO_INIT_RET_ERROR_INFO (ret_error);
190 go_plugin_service_load (service, &error);
191 if (error != NULL) {
192 *ret_error = go_error_info_new_str_with_details (
193 _("Error while loading plugin service."),
194 error);
195 return;
196 }
197 g_return_if_fail (service_general->cbs.plugin_func_init != NULL);
198 service_general->cbs.plugin_func_init (service, &error);
199 if (error != NULL) {
200 *ret_error = go_error_info_new_str_with_details (
201 _("Initializing function inside plugin returned error."),
202 error);
203 return;
204 }
205 service->is_active = TRUE;
206 }
207
208 static void
go_plugin_service_general_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)209 go_plugin_service_general_deactivate (GOPluginService *service, GOErrorInfo **ret_error)
210 {
211 GOPluginServiceGeneral *service_general = GO_PLUGIN_SERVICE_GENERAL (service);
212 GOErrorInfo *error = NULL;
213
214 GO_INIT_RET_ERROR_INFO (ret_error);
215 g_return_if_fail (service_general->cbs.plugin_func_cleanup != NULL);
216 service_general->cbs.plugin_func_cleanup (service, &error);
217 if (error != NULL) {
218 *ret_error = go_error_info_new_str_with_details (
219 _("Cleanup function inside plugin returned error."),
220 error);
221 return;
222 }
223 service->is_active = FALSE;
224 }
225
226 static char *
go_plugin_service_general_get_description(GOPluginService * service)227 go_plugin_service_general_get_description (GOPluginService *service)
228 {
229 return g_strdup (_("General"));
230 }
231
232 static void
go_plugin_service_general_class_init(GObjectClass * gobject_class)233 go_plugin_service_general_class_init (GObjectClass *gobject_class)
234 {
235 GOPluginServiceClass *plugin_service_class = GO_PLUGIN_SERVICE_CLASS (gobject_class);
236
237 plugin_service_class->activate = go_plugin_service_general_activate;
238 plugin_service_class->deactivate = go_plugin_service_general_deactivate;
239 plugin_service_class->get_description = go_plugin_service_general_get_description;
240 }
241
242 GSF_CLASS (GOPluginServiceGeneral, go_plugin_service_general,
243 go_plugin_service_general_class_init, go_plugin_service_general_init,
244 GO_TYPE_PLUGIN_SERVICE)
245
246 /****************************************************************************/
247
248 /*
249 * GOPluginServiceResource
250 */
251
252 typedef struct{
253 GOPluginServiceClass plugin_service_class;
254 } GOPluginServiceResourceClass;
255
256 struct _GOPluginServiceResource {
257 GOPluginService plugin_service;
258 char *id;
259 GString *value;
260 };
261
262 static GObjectClass *go_plugin_service_resource_parent_class;
263
264 static void
go_plugin_service_resource_init(GObject * obj)265 go_plugin_service_resource_init (GObject *obj)
266 {
267 }
268
269 static void
go_plugin_service_resource_finalize(GObject * obj)270 go_plugin_service_resource_finalize (GObject *obj)
271 {
272 GOPluginServiceResource *sr = GO_PLUGIN_SERVICE_RESOURCE (obj);
273
274 if (sr->value) {
275 g_string_free (sr->value, TRUE);
276 sr->value = NULL;
277 }
278
279 g_free (sr->id);
280 sr->id = NULL;
281
282 go_plugin_service_resource_parent_class->finalize (obj);
283 }
284
285 static void
go_plugin_service_resource_activate(GOPluginService * service,GOErrorInfo ** ret_error)286 go_plugin_service_resource_activate (GOPluginService *service, GOErrorInfo **ret_error)
287 {
288 GOPluginServiceResource *sr = GO_PLUGIN_SERVICE_RESOURCE (service);
289 if (sr->value) {
290 go_rsm_register_file (sr->id, sr->value->str, sr->value->len);
291 service->is_active = TRUE;
292 }
293 }
294
295
296 static void
go_plugin_service_resource_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)297 go_plugin_service_resource_deactivate (GOPluginService *service, GOErrorInfo **ret_error)
298 {
299 GOPluginServiceResource *sr = GO_PLUGIN_SERVICE_RESOURCE (service);
300 if (sr->value) {
301 go_rsm_unregister_file (sr->id);
302 service->is_active = FALSE;
303 }
304 }
305
306 static char *
go_plugin_service_resource_get_description(GOPluginService * service)307 go_plugin_service_resource_get_description (GOPluginService *service)
308 {
309 return g_strdup (_("Resource"));
310 }
311
312 static void
go_plugin_service_resource_read_xml(GOPluginService * service,xmlNode * tree,GOErrorInfo ** ret_error)313 go_plugin_service_resource_read_xml (GOPluginService *service, xmlNode *tree, GOErrorInfo **ret_error)
314 {
315 GOPluginServiceResource *sr = GO_PLUGIN_SERVICE_RESOURCE (service);
316 char *data = NULL;
317 gsize length;
318 xmlChar *file;
319
320 GO_INIT_RET_ERROR_INFO (ret_error);
321
322 sr->id = xml2c (go_xml_node_get_cstr (tree, "id"));
323 if (!sr->id)
324 goto error;
325
326 file = go_xml_node_get_cstr (tree, "file");
327 if (file) {
328 char *absfile;
329 gboolean ok;
330
331 if (!g_path_is_absolute (CXML2C (file))) {
332 char const *dir = go_plugin_get_dir_name
333 (go_plugin_service_get_plugin (service));
334 absfile = g_build_filename (dir, CXML2C (file), NULL);
335 } else
336 absfile = g_strdup (CXML2C (file));
337 xmlFree (file);
338 ok = g_file_get_contents (absfile, &data, &length, NULL);
339 g_free (absfile);
340
341 if (!ok)
342 goto error;
343 } else {
344 data = xml2c (go_xml_node_get_cstr (tree, "data"));
345 length = strlen (data);
346 }
347 if (!data)
348 goto error;
349
350 /* No encoding case */
351 sr->value = g_string_sized_new (length);
352 g_string_append_len (sr->value, data, length);
353 g_free (data);
354 return;
355
356 error:
357 *ret_error = go_error_info_new_str (_("Invalid resource service"));
358 g_free (data);
359 }
360
361 static void
go_plugin_service_resource_class_init(GObjectClass * gobject_class)362 go_plugin_service_resource_class_init (GObjectClass *gobject_class)
363 {
364 GOPluginServiceClass *plugin_service_class = GO_PLUGIN_SERVICE_CLASS (gobject_class);
365
366 go_plugin_service_resource_parent_class =
367 g_type_class_peek_parent (gobject_class);
368
369 gobject_class->finalize = go_plugin_service_resource_finalize;
370 plugin_service_class->activate = go_plugin_service_resource_activate;
371 plugin_service_class->deactivate = go_plugin_service_resource_deactivate;
372 plugin_service_class->get_description = go_plugin_service_resource_get_description;
373 plugin_service_class->read_xml = go_plugin_service_resource_read_xml;
374 }
375
376 GSF_CLASS (GOPluginServiceResource, go_plugin_service_resource,
377 go_plugin_service_resource_class_init,
378 go_plugin_service_resource_init,
379 GO_TYPE_PLUGIN_SERVICE)
380
381 /****************************************************************************/
382
383 /*
384 * GOPluginServiceFileOpener
385 */
386
387 typedef struct _GOPluginFileOpener GOPluginFileOpener;
388 static GOPluginFileOpener *go_plugin_file_opener_new (GOPluginService *service);
389
390 struct _InputFileSaveInfo {
391 gchar *saver_id_str;
392 GOFileFormatLevel format_level;
393 };
394
395 typedef struct _InputFileSaveInfo InputFileSaveInfo;
396
397
398 typedef struct{
399 GOPluginServiceClass plugin_service_class;
400 } GOPluginServiceFileOpenerClass;
401
402 struct _GOPluginServiceFileOpener {
403 GOPluginService plugin_service;
404
405 gint priority;
406 gboolean has_probe;
407 gboolean encoding_dependent;
408 gchar *description;
409 GSList *suffixes; /* list of char * */
410 GSList *mimes; /* list of char * */
411
412 GOFileOpener *opener;
413 GOPluginServiceFileOpenerCallbacks cbs;
414 };
415
416
417 static void
go_plugin_service_file_opener_init(GObject * obj)418 go_plugin_service_file_opener_init (GObject *obj)
419 {
420 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (obj);
421
422 GO_PLUGIN_SERVICE (obj)->cbs_ptr = &service_file_opener->cbs;
423 service_file_opener->description = NULL;
424 service_file_opener->suffixes = NULL;
425 service_file_opener->mimes = NULL;
426 service_file_opener->opener = NULL;
427 service_file_opener->cbs.plugin_func_file_probe = NULL;
428 service_file_opener->cbs.plugin_func_file_open = NULL;
429 }
430
431 static void
go_plugin_service_file_opener_finalize(GObject * obj)432 go_plugin_service_file_opener_finalize (GObject *obj)
433 {
434 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (obj);
435 GObjectClass *parent_class;
436
437 g_free (service_file_opener->description);
438 service_file_opener->description = NULL;
439 g_slist_free_full (service_file_opener->suffixes, g_free);
440 service_file_opener->suffixes = NULL;
441 g_slist_free_full (service_file_opener->mimes, g_free);
442 service_file_opener->mimes = NULL;
443 if (service_file_opener->opener != NULL) {
444 g_object_unref (service_file_opener->opener);
445 service_file_opener->opener = NULL;
446 }
447
448 parent_class = g_type_class_peek (GO_TYPE_PLUGIN_SERVICE);
449 parent_class->finalize (obj);
450 }
451
452 static void
go_plugin_service_file_opener_read_xml(GOPluginService * service,xmlNode * tree,GOErrorInfo ** ret_error)453 go_plugin_service_file_opener_read_xml (GOPluginService *service, xmlNode *tree, GOErrorInfo **ret_error)
454 {
455 int priority;
456 gboolean has_probe;
457 gboolean encoding_dependent;
458 xmlNode *information_node;
459 gchar *description;
460
461 GO_INIT_RET_ERROR_INFO (ret_error);
462 if (go_xml_node_get_int (tree, "priority", &priority))
463 priority = CLAMP (priority, 0, 100);
464 else
465 priority = 50;
466
467 if (!go_xml_node_get_bool (tree, "probe", &has_probe))
468 has_probe = TRUE;
469 if (!go_xml_node_get_bool (tree, "encoding_dependent", &encoding_dependent))
470 encoding_dependent = FALSE;
471
472 information_node = go_xml_get_child_by_name (tree, "information");
473 if (information_node != NULL) {
474 xmlNode *node = go_xml_get_child_by_name_by_lang
475 (information_node, "description");
476 description = node ? xml2c (xmlNodeGetContent (node)) : NULL;
477 } else {
478 description = NULL;
479 }
480 if (description != NULL) {
481 GSList *suffixes = NULL, *mimes = NULL;
482 xmlNode *list, *node;
483 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (service);
484
485 list = go_xml_get_child_by_name (tree, "suffixes");
486 if (list != NULL) {
487 for (node = list->xmlChildrenNode; node != NULL; node = node->next) {
488 char *tmp;
489
490 if (strcmp (node->name, "suffix"))
491 continue;
492
493 tmp = xml2c (xmlNodeGetContent (node));
494 if (!tmp)
495 continue;
496
497 GO_SLIST_PREPEND (suffixes, tmp);
498 }
499 }
500 GO_SLIST_REVERSE (suffixes);
501
502 list = go_xml_get_child_by_name (tree, "mime-types");
503 if (list != NULL) {
504 for (node = list->xmlChildrenNode; node != NULL; node = node->next) {
505 char *tmp;
506
507 if (strcmp (node->name, "mime-type"))
508 continue;
509
510 tmp = xml2c (xmlNodeGetContent (node));
511 if (!tmp)
512 continue;
513
514 GO_SLIST_PREPEND (mimes, tmp);
515 }
516 }
517 GO_SLIST_REVERSE (mimes);
518
519 service_file_opener->priority = priority;
520 service_file_opener->has_probe = has_probe;
521 service_file_opener->encoding_dependent = encoding_dependent;
522 service_file_opener->description = description;
523 service_file_opener->suffixes = suffixes;
524 service_file_opener->mimes = mimes;
525 } else {
526 *ret_error = go_error_info_new_str (_("File opener has no description"));
527 }
528 }
529
530 static void
go_plugin_service_file_opener_activate(GOPluginService * service,GOErrorInfo ** ret_error)531 go_plugin_service_file_opener_activate (GOPluginService *service,
532 GOErrorInfo **ret_error)
533 {
534 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (service);
535
536 GO_INIT_RET_ERROR_INFO (ret_error);
537 service_file_opener->opener = GO_FILE_OPENER (go_plugin_file_opener_new (service));
538 go_file_opener_register (service_file_opener->opener,
539 service_file_opener->priority);
540 service->is_active = TRUE;
541 }
542
543 static void
go_plugin_service_file_opener_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)544 go_plugin_service_file_opener_deactivate (GOPluginService *service,
545 GOErrorInfo **ret_error)
546 {
547 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (service);
548
549 GO_INIT_RET_ERROR_INFO (ret_error);
550 go_file_opener_unregister (service_file_opener->opener);
551 service->is_active = FALSE;
552 }
553
554 static char *
go_plugin_service_file_opener_get_description(GOPluginService * service)555 go_plugin_service_file_opener_get_description (GOPluginService *service)
556 {
557 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (service);
558
559 return g_strdup_printf (
560 _("File opener - %s"), service_file_opener->description);
561 }
562
563 static void
go_plugin_service_file_opener_class_init(GObjectClass * gobject_class)564 go_plugin_service_file_opener_class_init (GObjectClass *gobject_class)
565 {
566 GOPluginServiceClass *plugin_service_class = GO_PLUGIN_SERVICE_CLASS (gobject_class);
567
568 gobject_class->finalize = go_plugin_service_file_opener_finalize;
569 plugin_service_class->read_xml = go_plugin_service_file_opener_read_xml;
570 plugin_service_class->activate = go_plugin_service_file_opener_activate;
571 plugin_service_class->deactivate = go_plugin_service_file_opener_deactivate;
572 plugin_service_class->get_description = go_plugin_service_file_opener_get_description;
573 }
574
575 GSF_CLASS (GOPluginServiceFileOpener, go_plugin_service_file_opener,
576 go_plugin_service_file_opener_class_init,
577 go_plugin_service_file_opener_init,
578 GO_TYPE_PLUGIN_SERVICE)
579
580
581 /*** GOPluginFileOpener class ***/
582
583 #define TYPE_GO_PLUGIN_FILE_OPENER (go_plugin_file_opener_get_type ())
584 #define GO_PLUGIN_FILE_OPENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_GO_PLUGIN_FILE_OPENER, GOPluginFileOpener))
585 #define GO_PLUGIN_FILE_OPENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_GO_PLUGIN_FILE_OPENER, GOPluginFileOpenerClass))
586 #define GO_IS_PLUGIN_FILE_OPENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_GO_PLUGIN_FILE_OPENER))
587
588 GType go_plugin_file_opener_get_type (void);
589
590 typedef struct {
591 GOFileOpenerClass parent_class;
592 } GOPluginFileOpenerClass;
593
594 struct _GOPluginFileOpener {
595 GOFileOpener parent;
596
597 GOPluginService *service;
598 };
599
600 static void
go_plugin_file_opener_init(GOPluginFileOpener * fo)601 go_plugin_file_opener_init (GOPluginFileOpener *fo)
602 {
603 fo->service = NULL;
604 }
605
606 static gboolean
go_plugin_file_opener_can_probe(GOFileOpener const * fo,GOFileProbeLevel pl)607 go_plugin_file_opener_can_probe (GOFileOpener const *fo, GOFileProbeLevel pl)
608 {
609 GOPluginFileOpener *pfo = GO_PLUGIN_FILE_OPENER (fo);
610 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (pfo->service);
611 if (pl == GO_FILE_PROBE_FILE_NAME)
612 return service_file_opener->suffixes != NULL;
613 return service_file_opener->has_probe;
614 }
615
616 static gboolean
go_plugin_file_opener_probe(GOFileOpener const * fo,GsfInput * input,GOFileProbeLevel pl)617 go_plugin_file_opener_probe (GOFileOpener const *fo, GsfInput *input,
618 GOFileProbeLevel pl)
619 {
620 GOPluginFileOpener *pfo = GO_PLUGIN_FILE_OPENER (fo);
621 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (pfo->service);
622
623 g_return_val_if_fail (GSF_IS_INPUT (input), FALSE);
624
625 if (pl == GO_FILE_PROBE_FILE_NAME && service_file_opener->suffixes != NULL) {
626 GSList *ptr;
627 gchar const *extension;
628 gchar *lowercase_extension;
629
630 if (gsf_input_name (input) == NULL)
631 return FALSE;
632 extension = gsf_extension_pointer (gsf_input_name (input));
633 if (extension == NULL)
634 return FALSE;
635
636 lowercase_extension = g_utf8_strdown (extension, -1);
637 for (ptr = service_file_opener->suffixes; ptr != NULL ; ptr = ptr->next)
638 if (0 == strcmp (lowercase_extension, ptr->data))
639 break;
640 g_free (lowercase_extension);
641 return ptr != NULL;
642 }
643
644 if (service_file_opener->has_probe) {
645 GOErrorInfo *ignored_error = NULL;
646
647 go_plugin_service_load (pfo->service, &ignored_error);
648 if (ignored_error != NULL) {
649 go_error_info_print (ignored_error);
650 go_error_info_free (ignored_error);
651 return FALSE;
652 } else if (service_file_opener->cbs.plugin_func_file_probe == NULL) {
653 return FALSE;
654 } else {
655 gboolean res = service_file_opener->cbs.plugin_func_file_probe (fo, pfo->service, input, pl);
656 gsf_input_seek (input, 0, G_SEEK_SET);
657 return res;
658 }
659 } else {
660 return FALSE;
661 }
662 }
663
664 static void
go_plugin_file_opener_open(GOFileOpener const * fo,gchar const * enc,GOIOContext * io_context,GoView * view,GsfInput * input)665 go_plugin_file_opener_open (GOFileOpener const *fo, gchar const *enc,
666 GOIOContext *io_context,
667 GoView *view,
668 GsfInput *input)
669
670 {
671 GOPluginFileOpener *pfo = GO_PLUGIN_FILE_OPENER (fo);
672 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (pfo->service);
673 GOErrorInfo *error = NULL;
674
675 g_return_if_fail (GSF_IS_INPUT (input));
676
677 go_plugin_service_load (pfo->service, &error);
678 if (error != NULL) {
679 go_io_error_info_set (io_context, error);
680 go_io_error_push (io_context, go_error_info_new_str (
681 _("Error while reading file.")));
682 return;
683 }
684
685 g_return_if_fail (service_file_opener->cbs.plugin_func_file_open != NULL);
686 service_file_opener->cbs.plugin_func_file_open (fo, pfo->service, io_context, view, input, enc);
687 }
688
689 static void
go_plugin_file_opener_class_init(GOPluginFileOpenerClass * klass)690 go_plugin_file_opener_class_init (GOPluginFileOpenerClass *klass)
691 {
692 GOFileOpenerClass *go_file_opener_klass = GO_FILE_OPENER_CLASS (klass);
693
694 go_file_opener_klass->can_probe = go_plugin_file_opener_can_probe;
695 go_file_opener_klass->probe = go_plugin_file_opener_probe;
696 go_file_opener_klass->open = go_plugin_file_opener_open;
697 }
698
GSF_CLASS(GOPluginFileOpener,go_plugin_file_opener,go_plugin_file_opener_class_init,go_plugin_file_opener_init,GO_TYPE_FILE_OPENER)699 GSF_CLASS (GOPluginFileOpener, go_plugin_file_opener,
700 go_plugin_file_opener_class_init, go_plugin_file_opener_init,
701 GO_TYPE_FILE_OPENER)
702
703 static GSList *
704 go_str_slist_dup (GSList *l)
705 {
706 GSList *res = NULL;
707 for ( ; l != NULL ; l = l->next)
708 res = g_slist_prepend (res, g_strdup (l->data));
709 return g_slist_reverse (res);
710 }
711
712 static GOPluginFileOpener *
go_plugin_file_opener_new(GOPluginService * service)713 go_plugin_file_opener_new (GOPluginService *service)
714 {
715 GOPluginServiceFileOpener *service_file_opener = GO_PLUGIN_SERVICE_FILE_OPENER (service);
716 GOPluginFileOpener *fo;
717 gchar *opener_id;
718
719 opener_id = g_strconcat (
720 go_plugin_get_id (service->plugin), ":", service->id, NULL);
721 fo = GO_PLUGIN_FILE_OPENER (g_object_new (TYPE_GO_PLUGIN_FILE_OPENER, NULL));
722 go_file_opener_setup (GO_FILE_OPENER (fo), opener_id,
723 service_file_opener->description,
724 go_str_slist_dup (service_file_opener->suffixes),
725 go_str_slist_dup (service_file_opener->mimes),
726 service_file_opener->encoding_dependent, NULL, NULL);
727 fo->service = service;
728 g_free (opener_id);
729
730 return fo;
731 }
732
733 /*** -- ***/
734
735
736 /*
737 * GOPluginServiceFileSaver
738 */
739
740 typedef struct _GOPluginFileSaver GOPluginFileSaver;
741 static GOPluginFileSaver *go_plugin_file_saver_new (GOPluginService *service);
742
743
744 typedef struct{
745 GOPluginServiceClass plugin_service_class;
746 } GOPluginServiceFileSaverClass;
747
748 struct _GOPluginServiceFileSaver {
749 GOPluginService plugin_service;
750
751 gchar *file_extension;
752 gchar *mime_type;
753 GOFileFormatLevel format_level;
754 gchar *description;
755 gint default_saver_priority;
756 GOFileSaveScope save_scope;
757 gboolean overwrite_files;
758 gboolean interactive_only;
759 gboolean sheet_selection;
760
761 GOFileSaver *saver;
762 GOPluginServiceFileSaverCallbacks cbs;
763 };
764
765
766 static void
go_plugin_service_file_saver_init(GObject * obj)767 go_plugin_service_file_saver_init (GObject *obj)
768 {
769 GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (obj);
770
771 GO_PLUGIN_SERVICE (obj)->cbs_ptr = &service_file_saver->cbs;
772 service_file_saver->file_extension = NULL;
773 service_file_saver->mime_type = NULL;
774 service_file_saver->description = NULL;
775 service_file_saver->cbs.plugin_func_file_save = NULL;
776 service_file_saver->saver = NULL;
777 }
778
779 static void
go_plugin_service_file_saver_finalize(GObject * obj)780 go_plugin_service_file_saver_finalize (GObject *obj)
781 {
782 GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (obj);
783 GObjectClass *parent_class;
784
785 g_free (service_file_saver->file_extension);
786 g_free (service_file_saver->mime_type);
787 g_free (service_file_saver->description);
788 if (service_file_saver->saver != NULL)
789 g_object_unref (service_file_saver->saver);
790
791 parent_class = g_type_class_peek (GO_TYPE_PLUGIN_SERVICE);
792 parent_class->finalize (obj);
793 }
794
795 static void
go_plugin_service_file_saver_read_xml(GOPluginService * service,xmlNode * tree,GOErrorInfo ** ret_error)796 go_plugin_service_file_saver_read_xml (GOPluginService *service, xmlNode *tree, GOErrorInfo **ret_error)
797 {
798 xmlNode *information_node;
799 gchar *description;
800
801 GO_INIT_RET_ERROR_INFO (ret_error);
802 information_node = go_xml_get_child_by_name (tree, "information");
803 if (information_node != NULL) {
804 xmlNode *node = go_xml_get_child_by_name_by_lang
805 (information_node, "description");
806 description = node ? xml2c (xmlNodeGetContent (node)) : NULL;
807 } else {
808 description = NULL;
809 }
810
811 if (description != NULL) {
812 int scope = GO_FILE_SAVE_WORKBOOK;
813 int level = GO_FILE_FL_WRITE_ONLY;
814 GOPluginServiceFileSaver *psfs =
815 GO_PLUGIN_SERVICE_FILE_SAVER (service);
816
817 psfs->file_extension =
818 xml2c (go_xml_node_get_cstr (tree, "file_extension"));
819
820 psfs->mime_type =
821 xml2c (go_xml_node_get_cstr (tree, "mime_type"));
822
823 psfs->description = description;
824
825 (void)go_xml_node_get_enum
826 (tree, "format_level",
827 GO_TYPE_FILE_FORMAT_LEVEL, &level);
828 psfs->format_level = (GOFileFormatLevel)level;
829
830 if (!go_xml_node_get_int (tree, "default_saver_priority", &(psfs->default_saver_priority)))
831 psfs->default_saver_priority = -1;
832
833 (void)go_xml_node_get_enum
834 (tree, "save_scope",
835 GO_TYPE_FILE_SAVE_SCOPE, &scope);
836 psfs->save_scope = (GOFileSaveScope)scope;
837
838 if (!go_xml_node_get_bool (tree, "overwrite_files", &(psfs->overwrite_files)))
839 psfs->overwrite_files = TRUE;
840
841 if (!go_xml_node_get_bool (tree, "interactive_only", &(psfs->interactive_only)))
842 psfs->interactive_only = FALSE;
843
844 if (!go_xml_node_get_bool (tree, "sheet_selection", &(psfs->sheet_selection)))
845 psfs->sheet_selection = FALSE;
846 } else {
847 *ret_error = go_error_info_new_str (_("File saver has no description"));
848 }
849 }
850
851 static void
go_plugin_service_file_saver_activate(GOPluginService * service,GOErrorInfo ** ret_error)852 go_plugin_service_file_saver_activate (GOPluginService *service, GOErrorInfo **ret_error)
853 {
854 GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (service);
855 GHashTable *file_savers_hash;
856
857 GO_INIT_RET_ERROR_INFO (ret_error);
858 service_file_saver->saver = GO_FILE_SAVER (go_plugin_file_saver_new (service));
859 if (service_file_saver->default_saver_priority < 0) {
860 go_file_saver_register (service_file_saver->saver);
861 } else {
862 go_file_saver_register_as_default (service_file_saver->saver,
863 service_file_saver->default_saver_priority);
864 }
865 file_savers_hash = get_plugin_file_savers_hash (service->plugin);
866 g_assert (g_hash_table_lookup (file_savers_hash, service->id) == NULL);
867 g_hash_table_insert (file_savers_hash, g_strdup (service->id), service_file_saver->saver);
868 service->is_active = TRUE;
869 }
870
871 static void
go_plugin_service_file_saver_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)872 go_plugin_service_file_saver_deactivate (GOPluginService *service, GOErrorInfo **ret_error)
873 {
874 GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (service);
875 GHashTable *file_savers_hash;
876
877 GO_INIT_RET_ERROR_INFO (ret_error);
878 file_savers_hash = get_plugin_file_savers_hash (service->plugin);
879 g_hash_table_remove (file_savers_hash, service->id);
880 go_file_saver_unregister (service_file_saver->saver);
881 service->is_active = FALSE;
882 }
883
884 static char *
go_plugin_service_file_saver_get_description(GOPluginService * service)885 go_plugin_service_file_saver_get_description (GOPluginService *service)
886 {
887 GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (service);
888
889 return g_strdup_printf (
890 _("File saver - %s"), service_file_saver->description);
891 }
892
893 static void
go_plugin_service_file_saver_class_init(GObjectClass * gobject_class)894 go_plugin_service_file_saver_class_init (GObjectClass *gobject_class)
895 {
896 GOPluginServiceClass *plugin_service_class = GO_PLUGIN_SERVICE_CLASS (gobject_class);
897
898 gobject_class->finalize = go_plugin_service_file_saver_finalize;
899 plugin_service_class->read_xml = go_plugin_service_file_saver_read_xml;
900 plugin_service_class->activate = go_plugin_service_file_saver_activate;
901 plugin_service_class->deactivate = go_plugin_service_file_saver_deactivate;
902 plugin_service_class->get_description = go_plugin_service_file_saver_get_description;
903 }
904
905 GSF_CLASS (GOPluginServiceFileSaver, go_plugin_service_file_saver,
906 go_plugin_service_file_saver_class_init, go_plugin_service_file_saver_init,
907 GO_TYPE_PLUGIN_SERVICE)
908
909
910 /*** GOPluginFileSaver class ***/
911
912 #define TYPE_GO_PLUGIN_FILE_SAVER (go_plugin_file_saver_get_type ())
913 #define GO_PLUGIN_FILE_SAVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_GO_PLUGIN_FILE_SAVER, GOPluginFileSaver))
914 #define GO_PLUGIN_FILE_SAVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_GO_PLUGIN_FILE_SAVER, GOPluginFileSaverClass))
915 #define GO_IS_PLUGIN_FILE_SAVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_GO_PLUGIN_FILE_SAVER))
916
917 GType go_plugin_file_saver_get_type (void);
918
919 typedef struct {
920 GOFileSaverClass parent_class;
921 } GOPluginFileSaverClass;
922
923 struct _GOPluginFileSaver {
924 GOFileSaver parent;
925
926 GOPluginService *service;
927 };
928
929 static void
go_plugin_file_saver_init(GOPluginFileSaver * fs)930 go_plugin_file_saver_init (GOPluginFileSaver *fs)
931 {
932 fs->service = NULL;
933 }
934
935 static void
go_plugin_file_saver_save(GOFileSaver const * fs,GOIOContext * io_context,GoView const * view,GsfOutput * output)936 go_plugin_file_saver_save (GOFileSaver const *fs, GOIOContext *io_context,
937 GoView const *view,
938 GsfOutput *output)
939 {
940 GOPluginFileSaver *pfs = GO_PLUGIN_FILE_SAVER (fs);
941 GOPluginServiceFileSaver *service_file_saver = GO_PLUGIN_SERVICE_FILE_SAVER (pfs->service);
942 GOErrorInfo *error = NULL;
943
944 g_return_if_fail (GSF_IS_OUTPUT (output));
945
946 go_plugin_service_load (pfs->service, &error);
947 if (error != NULL) {
948 go_io_error_info_set (io_context, error);
949 go_io_error_push (io_context, go_error_info_new_str (
950 _("Error while loading plugin for saving.")));
951 if (!gsf_output_error (output))
952 gsf_output_set_error (output, 0, _("Failed to load plugin for saving"));
953 return;
954 }
955
956 g_return_if_fail (service_file_saver->cbs.plugin_func_file_save != NULL);
957 service_file_saver->cbs.plugin_func_file_save (fs, pfs->service, io_context, view, output);
958 }
959
960 static void
go_plugin_file_saver_class_init(GOPluginFileSaverClass * klass)961 go_plugin_file_saver_class_init (GOPluginFileSaverClass *klass)
962 {
963 GOFileSaverClass *go_file_saver_klass = GO_FILE_SAVER_CLASS (klass);
964
965 go_file_saver_klass->save = go_plugin_file_saver_save;
966 }
967
GSF_CLASS(GOPluginFileSaver,go_plugin_file_saver,go_plugin_file_saver_class_init,go_plugin_file_saver_init,GO_TYPE_FILE_SAVER)968 GSF_CLASS (GOPluginFileSaver, go_plugin_file_saver,
969 go_plugin_file_saver_class_init, go_plugin_file_saver_init,
970 GO_TYPE_FILE_SAVER)
971
972 static GOPluginFileSaver *
973 go_plugin_file_saver_new (GOPluginService *service)
974 {
975 GOPluginFileSaver *pfs;
976 GOPluginServiceFileSaver *psfs = GO_PLUGIN_SERVICE_FILE_SAVER (service);
977 gchar *saver_id;
978
979 saver_id = g_strconcat (go_plugin_get_id (service->plugin),
980 ":",
981 service->id,
982 NULL);
983 pfs = GO_PLUGIN_FILE_SAVER (g_object_new
984 (TYPE_GO_PLUGIN_FILE_SAVER,
985 "id", saver_id,
986 "extension", psfs->file_extension,
987 "mime-type", psfs->mime_type,
988 "description", psfs->description,
989 "format-level", psfs->format_level,
990 "overwrite", psfs->overwrite_files,
991 "interactive-only", psfs->interactive_only,
992 "scope", psfs->save_scope,
993 "sheet-selection", psfs->sheet_selection,
994 NULL));
995
996 pfs->service = service;
997 g_free (saver_id);
998
999 return pfs;
1000 }
1001
1002 /*
1003 * GOPluginServicePluginLoader
1004 */
1005
1006 typedef struct{
1007 GOPluginServiceClass plugin_service_class;
1008 } GOPluginServicePluginLoaderClass;
1009
1010 struct _GOPluginServicePluginLoader {
1011 GOPluginService plugin_service;
1012 GOPluginServicePluginLoaderCallbacks cbs;
1013 };
1014
1015
1016 static void
go_plugin_service_plugin_loader_init(GObject * obj)1017 go_plugin_service_plugin_loader_init (GObject *obj)
1018 {
1019 GOPluginServicePluginLoader *service_plugin_loader = GO_PLUGIN_SERVICE_PLUGIN_LOADER (obj);
1020
1021 GO_PLUGIN_SERVICE (obj)->cbs_ptr = &service_plugin_loader->cbs;
1022 }
1023
1024 GType
go_plugin_service_plugin_loader_generate_type(GOPluginService * service,GOErrorInfo ** ret_error)1025 go_plugin_service_plugin_loader_generate_type (GOPluginService *service,
1026 GOErrorInfo **ret_error)
1027 {
1028 GOPluginServicePluginLoader *service_plugin_loader = GO_PLUGIN_SERVICE_PLUGIN_LOADER (service);
1029 GOErrorInfo *error = NULL;
1030 GType loader_type;
1031
1032 GO_INIT_RET_ERROR_INFO (ret_error);
1033 go_plugin_service_load (service, &error);
1034 if (error == NULL) {
1035 loader_type = service_plugin_loader->cbs.plugin_func_get_loader_type (
1036 service, &error);
1037 if (error == NULL)
1038 return loader_type;
1039 *ret_error = error;
1040 } else {
1041 *ret_error = go_error_info_new_str_with_details (
1042 _("Error while loading plugin service."),
1043 error);
1044 }
1045 return G_TYPE_NONE;
1046 }
1047
1048 static void
go_plugin_service_plugin_loader_activate(GOPluginService * service,GOErrorInfo ** ret_error)1049 go_plugin_service_plugin_loader_activate (GOPluginService *service,
1050 GOErrorInfo **ret_error)
1051 {
1052 gchar *full_id;
1053
1054 GO_INIT_RET_ERROR_INFO (ret_error);
1055 full_id = g_strconcat (
1056 go_plugin_get_id (service->plugin), ":", service->id, NULL);
1057 go_plugins_register_loader (full_id, service);
1058 g_free (full_id);
1059 service->is_active = TRUE;
1060 }
1061
1062 static void
go_plugin_service_plugin_loader_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)1063 go_plugin_service_plugin_loader_deactivate (GOPluginService *service,
1064 GOErrorInfo **ret_error)
1065 {
1066 gchar *full_id;
1067
1068 GO_INIT_RET_ERROR_INFO (ret_error);
1069 full_id = g_strconcat (
1070 go_plugin_get_id (service->plugin), ":", service->id, NULL);
1071 go_plugins_unregister_loader (full_id);
1072 g_free (full_id);
1073 service->is_active = FALSE;
1074 }
1075
1076 static char *
go_plugin_service_plugin_loader_get_description(GOPluginService * service)1077 go_plugin_service_plugin_loader_get_description (GOPluginService *service)
1078 {
1079 return g_strdup (_("Plugin loader"));
1080 }
1081
1082 static void
go_plugin_service_plugin_loader_class_init(GObjectClass * gobject_class)1083 go_plugin_service_plugin_loader_class_init (GObjectClass *gobject_class)
1084 {
1085 GOPluginServiceClass *plugin_service_class = GO_PLUGIN_SERVICE_CLASS (gobject_class);
1086
1087 plugin_service_class->activate = go_plugin_service_plugin_loader_activate;
1088 plugin_service_class->deactivate = go_plugin_service_plugin_loader_deactivate;
1089 plugin_service_class->get_description = go_plugin_service_plugin_loader_get_description;
1090 }
1091
GSF_CLASS(GOPluginServicePluginLoader,go_plugin_service_plugin_loader,go_plugin_service_plugin_loader_class_init,go_plugin_service_plugin_loader_init,GO_TYPE_PLUGIN_SERVICE)1092 GSF_CLASS (GOPluginServicePluginLoader, go_plugin_service_plugin_loader,
1093 go_plugin_service_plugin_loader_class_init,
1094 go_plugin_service_plugin_loader_init,
1095 GO_TYPE_PLUGIN_SERVICE)
1096
1097 /**************************************************************************
1098 * GOPluginServiceGObjectLoader
1099 */
1100
1101 static char *
1102 go_plugin_service_gobject_loader_get_description (GOPluginService *service)
1103 {
1104 return g_strdup (_("GObject loader"));
1105 }
1106
1107 static void
go_plugin_service_gobject_loader_read_xml(GOPluginService * service,G_GNUC_UNUSED xmlNode * tree,G_GNUC_UNUSED GOErrorInfo ** ret_error)1108 go_plugin_service_gobject_loader_read_xml (GOPluginService *service,
1109 G_GNUC_UNUSED xmlNode *tree,
1110 G_GNUC_UNUSED GOErrorInfo **ret_error)
1111 {
1112 GOPluginServiceGObjectLoaderClass *gobj_loader_class = GO_PLUGIN_SERVICE_GOBJECT_LOADER_GET_CLASS (service);
1113 g_return_if_fail (gobj_loader_class->pending != NULL);
1114 g_hash_table_replace (gobj_loader_class->pending, service->id, service);
1115 }
1116
1117 static void
go_plugin_service_gobject_loader_class_init(GOPluginServiceGObjectLoaderClass * gobj_loader_class)1118 go_plugin_service_gobject_loader_class_init (GOPluginServiceGObjectLoaderClass *gobj_loader_class)
1119 {
1120 GOPluginServiceClass *psc = GO_PLUGIN_SERVICE_CLASS (gobj_loader_class);
1121
1122 psc->get_description = go_plugin_service_gobject_loader_get_description;
1123 psc->read_xml = go_plugin_service_gobject_loader_read_xml;
1124 gobj_loader_class->pending = NULL;
1125 }
1126
GSF_CLASS(GOPluginServiceGObjectLoader,go_plugin_service_gobject_loader,go_plugin_service_gobject_loader_class_init,NULL,GO_TYPE_PLUGIN_SERVICE_SIMPLE)1127 GSF_CLASS (GOPluginServiceGObjectLoader, go_plugin_service_gobject_loader,
1128 go_plugin_service_gobject_loader_class_init, NULL,
1129 GO_TYPE_PLUGIN_SERVICE_SIMPLE)
1130
1131 /**************************************************************************
1132 * GOPluginServiceSimple
1133 */
1134
1135 static void
1136 go_plugin_service_simple_activate (GOPluginService *service, GOErrorInfo **ret_error)
1137 {
1138 service->is_active = TRUE;
1139 }
1140
1141 static void
go_plugin_service_simple_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)1142 go_plugin_service_simple_deactivate (GOPluginService *service, GOErrorInfo **ret_error)
1143 {
1144 service->is_active = FALSE;
1145 }
1146
1147 static void
go_plugin_service_simple_class_init(GObjectClass * gobject_class)1148 go_plugin_service_simple_class_init (GObjectClass *gobject_class)
1149 {
1150 GOPluginServiceClass *psc = GO_PLUGIN_SERVICE_CLASS (gobject_class);
1151
1152 psc->activate = go_plugin_service_simple_activate;
1153 psc->deactivate = go_plugin_service_simple_deactivate;
1154 }
1155
GSF_CLASS(GOPluginServiceSimple,go_plugin_service_simple,go_plugin_service_simple_class_init,NULL,GO_TYPE_PLUGIN_SERVICE)1156 GSF_CLASS (GOPluginServiceSimple, go_plugin_service_simple,
1157 go_plugin_service_simple_class_init,
1158 NULL,
1159 GO_TYPE_PLUGIN_SERVICE)
1160
1161 /* ---------------------------------------------------------------------- */
1162
1163 void
1164 go_plugin_service_load (GOPluginService *service, GOErrorInfo **ret_error)
1165 {
1166 g_return_if_fail (GO_IS_PLUGIN_SERVICE (service));
1167
1168 GO_INIT_RET_ERROR_INFO (ret_error);
1169
1170 if (service->is_loaded)
1171 return;
1172 go_plugin_load_service (service->plugin, service, ret_error);
1173 if (*ret_error == NULL)
1174 service->is_loaded = TRUE;
1175 }
1176
1177 void
go_plugin_service_unload(GOPluginService * service,GOErrorInfo ** ret_error)1178 go_plugin_service_unload (GOPluginService *service, GOErrorInfo **ret_error)
1179 {
1180 GOErrorInfo *error = NULL;
1181
1182 g_return_if_fail (GO_IS_PLUGIN_SERVICE (service));
1183
1184 GO_INIT_RET_ERROR_INFO (ret_error);
1185 if (!service->is_loaded) {
1186 return;
1187 }
1188 go_plugin_unload_service (service->plugin, service, &error);
1189 if (error == NULL) {
1190 service->is_loaded = FALSE;
1191 } else {
1192 *ret_error = error;
1193 }
1194 }
1195
1196 GOPluginService *
go_plugin_service_new(GOPlugin * plugin,xmlNode * tree,GOErrorInfo ** ret_error)1197 go_plugin_service_new (GOPlugin *plugin, xmlNode *tree, GOErrorInfo **ret_error)
1198 {
1199 GOPluginService *service = NULL;
1200 char *type_str;
1201 GOErrorInfo *service_error = NULL;
1202 GOPluginServiceCreate ctor;
1203
1204 g_return_val_if_fail (GO_IS_PLUGIN (plugin), NULL);
1205 g_return_val_if_fail (tree != NULL, NULL);
1206 g_return_val_if_fail (strcmp (tree->name, "service") == 0, NULL);
1207
1208 GO_INIT_RET_ERROR_INFO (ret_error);
1209 type_str = go_xml_node_get_cstr (tree, "type");
1210 if (type_str == NULL) {
1211 *ret_error = go_error_info_new_str (_("No \"type\" attribute on \"service\" element."));
1212 return NULL;
1213 }
1214
1215 ctor = g_hash_table_lookup (services, type_str);
1216 if (ctor == NULL) {
1217 *ret_error = go_error_info_new_printf (_("Unknown service type: %s."), type_str);
1218 xmlFree (type_str);
1219 return NULL;
1220 }
1221 xmlFree (type_str);
1222
1223 service = g_object_new (ctor(), NULL);
1224 service->plugin = plugin;
1225 service->id = xml2c (go_xml_node_get_cstr (tree, "id"));
1226 if (service->id == NULL)
1227 service->id = xmlStrdup ("default");
1228
1229 if (GO_PLUGIN_SERVICE_GET_CLASS (service)->read_xml != NULL) {
1230 GO_PLUGIN_SERVICE_GET_CLASS (service)->read_xml (service, tree, &service_error);
1231 if (service_error != NULL) {
1232 *ret_error = go_error_info_new_str_with_details (
1233 _("Error reading service information."), service_error);
1234 g_object_unref (service);
1235 service = NULL;
1236 }
1237 }
1238
1239 return service;
1240 }
1241
1242 char const *
go_plugin_service_get_id(const GOPluginService * service)1243 go_plugin_service_get_id (const GOPluginService *service)
1244 {
1245 g_return_val_if_fail (GO_IS_PLUGIN_SERVICE (service), NULL);
1246
1247 return service->id;
1248 }
1249
1250 char const *
go_plugin_service_get_description(GOPluginService * service)1251 go_plugin_service_get_description (GOPluginService *service)
1252 {
1253 g_return_val_if_fail (GO_IS_PLUGIN_SERVICE (service), NULL);
1254
1255 if (service->saved_description == NULL) {
1256 service->saved_description = GO_PLUGIN_SERVICE_GET_CLASS (service)->get_description (service);
1257 }
1258
1259 return service->saved_description;
1260 }
1261
1262 /**
1263 * go_plugin_service_get_plugin:
1264 * @service: #GOPluginService
1265 *
1266 * Returns: (transfer none): the plugin offering @service
1267 **/
1268 GOPlugin *
go_plugin_service_get_plugin(GOPluginService * service)1269 go_plugin_service_get_plugin (GOPluginService *service)
1270 {
1271 g_return_val_if_fail (GO_IS_PLUGIN_SERVICE (service), NULL);
1272
1273 return service->plugin;
1274 }
1275
1276 /**
1277 * go_plugin_service_get_cbs:
1278 * @service: #GOPluginService
1279 *
1280 * Returns: (transfer none): the callbacks for the service
1281 **/
1282 gpointer
go_plugin_service_get_cbs(GOPluginService * service)1283 go_plugin_service_get_cbs (GOPluginService *service)
1284 {
1285 g_return_val_if_fail (GO_IS_PLUGIN_SERVICE (service), NULL);
1286 g_return_val_if_fail (service->cbs_ptr != NULL, NULL);
1287
1288 return service->cbs_ptr;
1289 }
1290
1291 void
go_plugin_service_activate(GOPluginService * service,GOErrorInfo ** ret_error)1292 go_plugin_service_activate (GOPluginService *service, GOErrorInfo **ret_error)
1293 {
1294 g_return_if_fail (GO_IS_PLUGIN_SERVICE (service));
1295
1296 GO_INIT_RET_ERROR_INFO (ret_error);
1297 if (service->is_active) {
1298 return;
1299 }
1300 #ifdef PLUGIN_ALWAYS_LOAD
1301 {
1302 GOErrorInfo *load_error = NULL;
1303
1304 go_plugin_service_load (service, &load_error);
1305 if (load_error != NULL) {
1306 *ret_error = go_error_info_new_str_with_details (
1307 _("We must load service before activating it (PLUGIN_ALWAYS_LOAD is set) "
1308 "but loading failed."), load_error);
1309 return;
1310 }
1311 }
1312 #endif
1313 GO_PLUGIN_SERVICE_GET_CLASS (service)->activate (service, ret_error);
1314 }
1315
1316 void
go_plugin_service_deactivate(GOPluginService * service,GOErrorInfo ** ret_error)1317 go_plugin_service_deactivate (GOPluginService *service, GOErrorInfo **ret_error)
1318 {
1319 g_return_if_fail (GO_IS_PLUGIN_SERVICE (service));
1320
1321 GO_INIT_RET_ERROR_INFO (ret_error);
1322 if (!service->is_active) {
1323 return;
1324 }
1325 GO_PLUGIN_SERVICE_GET_CLASS (service)->deactivate (service, ret_error);
1326 if (*ret_error == NULL) {
1327 GOErrorInfo *ignored_error = NULL;
1328
1329 service->is_active = FALSE;
1330 /* FIXME */
1331 go_plugin_service_unload (service, &ignored_error);
1332 go_error_info_free (ignored_error);
1333 }
1334 }
1335
1336 /*****************************************************************************/
1337
1338 void
_go_plugin_services_init(void)1339 _go_plugin_services_init (void)
1340 {
1341 static struct {
1342 char const *type_str;
1343 GOPluginServiceCreate ctor;
1344 } const builtin_services[] = {
1345 { "general", go_plugin_service_general_get_type},
1346 { "resource", go_plugin_service_resource_get_type},
1347 { "file_opener", go_plugin_service_file_opener_get_type},
1348 { "file_saver", go_plugin_service_file_saver_get_type},
1349 { "plugin_loader", go_plugin_service_plugin_loader_get_type},
1350 /* base classes, not really for direct external use,
1351 * put here for expositional purposes
1352 */
1353 #if 0
1354 { "gobject_loader", go_plugin_service_gobject_loader_get_type}
1355 { "simple", go_plugin_service_simple_get_type}
1356 #endif
1357 };
1358 unsigned i;
1359
1360 g_return_if_fail (services == NULL);
1361
1362 services = g_hash_table_new (g_str_hash, g_str_equal);
1363 for (i = 0; i < G_N_ELEMENTS (builtin_services); i++)
1364 go_plugin_service_define (builtin_services[i].type_str,
1365 builtin_services[i].ctor);
1366 }
1367
1368 void
go_plugin_services_shutdown(void)1369 go_plugin_services_shutdown (void)
1370 {
1371 g_return_if_fail (services != NULL);
1372 g_hash_table_destroy (services);
1373 services = NULL;
1374 }
1375
1376 /**
1377 * go_plugin_service_define:
1378 * @type_str: char const *
1379 * @ctor: (scope async): #GOPluginServiceCreate
1380 *
1381 * Allow the definition of new service types
1382 **/
1383 void
go_plugin_service_define(char const * type_str,GOPluginServiceCreate ctor)1384 go_plugin_service_define (char const *type_str, GOPluginServiceCreate ctor)
1385 {
1386 g_return_if_fail (services != NULL);
1387
1388 g_return_if_fail (NULL == g_hash_table_lookup (services, type_str));
1389
1390 g_hash_table_insert (services, (gpointer)type_str, ctor);
1391 }
1392