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