4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
29 typedef struct _PurplePluginInfoPrivate PurplePluginInfoPrivate
;
31 /**************************************************************************
32 * Plugin info private data
33 **************************************************************************/
34 struct _PurplePluginInfoPrivate
{
35 char *ui_requirement
; /* ID of UI that is required to load the plugin */
36 char *error
; /* Why a plugin is not loadable */
38 PurplePluginInfoFlags flags
; /* Flags for the plugin */
40 /* Callback that returns a list of actions the plugin can perform */
41 PurplePluginActionsCb actions_cb
;
43 /* Callback that returns extra information about a plugin */
44 PurplePluginExtraCb extra_cb
;
46 /* Callback that returns a preferences frame for a plugin */
47 PurplePluginPrefFrameCb pref_frame_cb
;
49 /* Callback that returns a preferences request handle for a plugin */
50 PurplePluginPrefRequestCb pref_request_cb
;
52 /* TRUE if a plugin has been unloaded at least once. Auto-load
53 * plugins that have been unloaded once will not be auto-loaded again. */
69 G_DEFINE_TYPE_WITH_PRIVATE(PurplePluginInfo
, purple_plugin_info
,
70 GPLUGIN_TYPE_PLUGIN_INFO
);
72 /**************************************************************************
74 **************************************************************************/
75 static GList
*loaded_plugins
= NULL
;
76 static GList
*plugins_to_disable
= NULL
;
78 /**************************************************************************
80 **************************************************************************/
82 plugin_loading_cb(GObject
*manager
, PurplePlugin
*plugin
, GError
**error
,
85 PurplePluginInfo
*info
;
86 PurplePluginInfoPrivate
*priv
;
88 g_return_val_if_fail(PURPLE_IS_PLUGIN(plugin
), FALSE
);
90 info
= purple_plugin_get_info(plugin
);
92 return TRUE
; /* a GPlugin internal plugin */
94 priv
= purple_plugin_info_get_instance_private(info
);
97 purple_debug_error("plugins", "Failed to load plugin %s: %s",
98 purple_plugin_get_filename(plugin
), priv
->error
);
100 g_set_error(error
, PURPLE_PLUGINS_DOMAIN
, 0,
101 "Plugin is not loadable: %s", priv
->error
);
110 plugin_loaded_cb(GObject
*manager
, PurplePlugin
*plugin
)
112 PurplePluginInfo
*info
;
114 g_return_if_fail(PURPLE_IS_PLUGIN(plugin
));
116 info
= purple_plugin_get_info(plugin
);
118 return; /* a GPlugin internal plugin */
120 loaded_plugins
= g_list_prepend(loaded_plugins
, plugin
);
122 purple_debug_info("plugins", "Loaded plugin %s\n",
123 purple_plugin_get_filename(plugin
));
125 purple_signal_emit(purple_plugins_get_handle(), "plugin-load", plugin
);
129 plugin_unloading_cb(GObject
*manager
, PurplePlugin
*plugin
, GError
**error
,
132 PurplePluginInfo
*info
;
134 g_return_val_if_fail(PURPLE_IS_PLUGIN(plugin
), FALSE
);
136 info
= purple_plugin_get_info(plugin
);
138 purple_debug_info("plugins", "Unloading plugin %s\n",
139 purple_plugin_get_filename(plugin
));
146 plugin_unloaded_cb(GObject
*manager
, PurplePlugin
*plugin
)
148 PurplePluginInfo
*info
;
149 PurplePluginInfoPrivate
*priv
;
151 g_return_if_fail(PURPLE_IS_PLUGIN(plugin
));
153 info
= purple_plugin_get_info(plugin
);
155 return; /* a GPlugin internal plugin */
157 priv
= purple_plugin_info_get_instance_private(info
);
159 /* cancel any pending dialogs the plugin has */
160 purple_request_close_with_handle(plugin
);
161 purple_notify_close_with_handle(plugin
);
163 purple_signals_disconnect_by_handle(plugin
);
164 purple_signals_unregister_by_instance(plugin
);
166 priv
->unloaded
= TRUE
;
168 loaded_plugins
= g_list_remove(loaded_plugins
, plugin
);
169 plugins_to_disable
= g_list_remove(plugins_to_disable
, plugin
);
171 purple_signal_emit(purple_plugins_get_handle(), "plugin-unload", plugin
);
173 purple_prefs_disconnect_by_handle(plugin
);
177 purple_plugin_load(PurplePlugin
*plugin
, GError
**error
)
181 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
183 if (purple_plugin_is_loaded(plugin
))
186 if (!gplugin_manager_load_plugin(plugin
, &err
)) {
187 purple_debug_error("plugins", "Failed to load plugin %s: %s",
188 purple_plugin_get_filename(plugin
),
189 (err
? err
->message
: "Unknown reason"));
192 *error
= g_error_copy(err
);
202 purple_plugin_unload(PurplePlugin
*plugin
, GError
**error
)
206 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
208 if (!purple_plugin_is_loaded(plugin
))
211 if (!gplugin_manager_unload_plugin(plugin
, &err
)) {
212 purple_debug_error("plugins", "Failed to unload plugin %s: %s",
213 purple_plugin_get_filename(plugin
),
214 (err
? err
->message
: "Unknown reason"));
217 *error
= g_error_copy(err
);
227 purple_plugin_is_loaded(PurplePlugin
*plugin
)
229 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
231 return (gplugin_plugin_get_state(plugin
) == GPLUGIN_PLUGIN_STATE_LOADED
);
235 purple_plugin_get_filename(PurplePlugin
*plugin
)
237 g_return_val_if_fail(plugin
!= NULL
, NULL
);
239 return gplugin_plugin_get_filename(plugin
);
243 purple_plugin_get_info(PurplePlugin
*plugin
)
245 GPluginPluginInfo
*info
;
247 g_return_val_if_fail(plugin
!= NULL
, NULL
);
249 info
= gplugin_plugin_get_info(plugin
);
251 /* GPlugin refs the plugin info object before returning it. This workaround
252 * is to avoid managing the reference counts everywhere in our codebase
253 * where we use the plugin info. The plugin info instance is guaranteed to
254 * exist as long as the plugin exists. */
255 g_object_unref(info
);
257 if (PURPLE_IS_PLUGIN_INFO(info
))
258 return PURPLE_PLUGIN_INFO(info
);
264 purple_plugin_disable(PurplePlugin
*plugin
)
266 g_return_if_fail(plugin
!= NULL
);
268 if (!g_list_find(plugins_to_disable
, plugin
))
269 plugins_to_disable
= g_list_prepend(plugins_to_disable
, plugin
);
273 purple_plugin_register_type(PurplePlugin
*plugin
, GType parent
,
274 const gchar
*name
, const GTypeInfo
*info
,
277 g_return_val_if_fail(G_IS_TYPE_MODULE(plugin
), G_TYPE_INVALID
);
279 return g_type_module_register_type(G_TYPE_MODULE(plugin
),
280 parent
, name
, info
, flags
);
284 purple_plugin_add_interface(PurplePlugin
*plugin
, GType instance_type
,
285 GType interface_type
,
286 const GInterfaceInfo
*interface_info
)
288 g_return_if_fail(G_IS_TYPE_MODULE(plugin
));
290 g_type_module_add_interface(G_TYPE_MODULE(plugin
),
291 instance_type
, interface_type
,
296 purple_plugin_is_internal(PurplePlugin
*plugin
)
298 PurplePluginInfo
*info
;
300 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
302 info
= purple_plugin_get_info(plugin
);
306 return (purple_plugin_info_get_flags(info
) &
307 PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
);
311 purple_plugin_get_dependent_plugins(PurplePlugin
*plugin
)
313 #warning TODO: Implement this when GPlugin can return dependent plugins.
317 /**************************************************************************
318 * GObject code for PurplePluginInfo
319 **************************************************************************/
320 /* GObject initialization function */
322 purple_plugin_info_init(PurplePluginInfo
*info
)
326 /* Set method for GObject properties */
328 purple_plugin_info_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
331 PurplePluginInfo
*info
= PURPLE_PLUGIN_INFO(obj
);
332 PurplePluginInfoPrivate
*priv
=
333 purple_plugin_info_get_instance_private(info
);
336 case PROP_UI_REQUIREMENT
:
337 priv
->ui_requirement
= g_value_dup_string(value
);
339 case PROP_ACTIONS_CB
:
340 priv
->actions_cb
= g_value_get_pointer(value
);
343 priv
->extra_cb
= g_value_get_pointer(value
);
345 case PROP_PREF_FRAME_CB
:
346 priv
->pref_frame_cb
= g_value_get_pointer(value
);
348 case PROP_PREF_REQUEST_CB
:
349 priv
->pref_request_cb
= g_value_get_pointer(value
);
352 priv
->flags
= g_value_get_flags(value
);
355 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
360 /* Get method for GObject properties */
362 purple_plugin_info_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
365 PurplePluginInfo
*info
= PURPLE_PLUGIN_INFO(obj
);
368 case PROP_ACTIONS_CB
:
369 g_value_set_pointer(value
,
370 purple_plugin_info_get_actions_cb(info
));
373 g_value_set_pointer(value
,
374 purple_plugin_info_get_extra_cb(info
));
376 case PROP_PREF_FRAME_CB
:
377 g_value_set_pointer(value
,
378 purple_plugin_info_get_pref_frame_cb(info
));
380 case PROP_PREF_REQUEST_CB
:
381 g_value_set_pointer(value
,
382 purple_plugin_info_get_pref_request_cb(info
));
385 g_value_set_flags(value
, purple_plugin_info_get_flags(info
));
388 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
393 /* Called when done constructing */
395 purple_plugin_info_constructed(GObject
*object
)
397 PurplePluginInfo
*info
= PURPLE_PLUGIN_INFO(object
);
398 PurplePluginInfoPrivate
*priv
=
399 purple_plugin_info_get_instance_private(info
);
400 const char *id
= purple_plugin_info_get_id(info
);
403 G_OBJECT_CLASS(purple_plugin_info_parent_class
)->constructed(object
);
405 if (id
== NULL
|| *id
== '\0')
406 priv
->error
= g_strdup(_("This plugin has not defined an ID."));
408 if (priv
->ui_requirement
&& !purple_strequal(priv
->ui_requirement
, purple_core_get_ui()))
410 priv
->error
= g_strdup_printf(_("You are using %s, but this plugin requires %s."),
411 purple_core_get_ui(), priv
->ui_requirement
);
412 purple_debug_error("plugins", "%s is not loadable: The UI requirement is not met. (%s)\n",
416 version
= purple_plugin_info_get_abi_version(info
);
417 if (PURPLE_PLUGIN_ABI_MAJOR_VERSION(version
) != PURPLE_MAJOR_VERSION
||
418 PURPLE_PLUGIN_ABI_MINOR_VERSION(version
) > PURPLE_MINOR_VERSION
)
420 priv
->error
= g_strdup_printf(_("Your libpurple version is %d.%d.x (need %d.%d.x)"),
421 PURPLE_MAJOR_VERSION
, PURPLE_MINOR_VERSION
,
422 PURPLE_PLUGIN_ABI_MAJOR_VERSION(version
),
423 PURPLE_PLUGIN_ABI_MINOR_VERSION(version
));
424 purple_debug_error("plugins", "%s is not loadable: libpurple version is %d.%d.x (need %d.%d.x)\n",
425 id
, PURPLE_MAJOR_VERSION
, PURPLE_MINOR_VERSION
,
426 PURPLE_PLUGIN_ABI_MAJOR_VERSION(version
),
427 PURPLE_PLUGIN_ABI_MINOR_VERSION(version
));
431 /* GObject finalize function */
433 purple_plugin_info_finalize(GObject
*object
)
435 PurplePluginInfoPrivate
*priv
=
436 purple_plugin_info_get_instance_private(
437 PURPLE_PLUGIN_INFO(object
));
439 g_free(priv
->ui_requirement
);
442 G_OBJECT_CLASS(purple_plugin_info_parent_class
)->finalize(object
);
445 /* Class initializer function */
446 static void purple_plugin_info_class_init(PurplePluginInfoClass
*klass
)
448 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
450 obj_class
->constructed
= purple_plugin_info_constructed
;
451 obj_class
->finalize
= purple_plugin_info_finalize
;
453 /* Setup properties */
454 obj_class
->get_property
= purple_plugin_info_get_property
;
455 obj_class
->set_property
= purple_plugin_info_set_property
;
457 g_object_class_install_property(obj_class
, PROP_UI_REQUIREMENT
,
458 g_param_spec_string("ui-requirement",
460 "ID of UI that is required by this plugin", NULL
,
461 G_PARAM_WRITABLE
| G_PARAM_STATIC_STRINGS
));
463 g_object_class_install_property(obj_class
, PROP_ACTIONS_CB
,
464 g_param_spec_pointer("actions-cb",
466 "Callback that returns list of plugin's actions",
467 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
468 G_PARAM_STATIC_STRINGS
));
470 g_object_class_install_property(obj_class
, PROP_EXTRA_CB
,
471 g_param_spec_pointer("extra-cb",
472 "Extra info callback",
473 "Callback that returns extra info about the plugin",
474 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
475 G_PARAM_STATIC_STRINGS
));
477 g_object_class_install_property(obj_class
, PROP_PREF_FRAME_CB
,
478 g_param_spec_pointer("pref-frame-cb",
479 "Preferences frame callback",
480 "The callback that returns the preferences frame",
481 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
482 G_PARAM_STATIC_STRINGS
));
484 g_object_class_install_property(obj_class
, PROP_PREF_REQUEST_CB
,
485 g_param_spec_pointer("pref-request-cb",
486 "Preferences request callback",
487 "Callback that returns preferences request handle",
488 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
489 G_PARAM_STATIC_STRINGS
));
491 g_object_class_install_property(obj_class
, PROP_FLAGS
,
492 g_param_spec_flags("flags",
494 "The flags for the plugin",
495 PURPLE_TYPE_PLUGIN_INFO_FLAGS
, 0,
496 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
497 G_PARAM_STATIC_STRINGS
));
500 /**************************************************************************
502 **************************************************************************/
504 purple_plugin_info_new(const char *first_property
, ...)
509 /* at least ID is required */
513 va_start(var_args
, first_property
);
514 info
= g_object_new_valist(PURPLE_TYPE_PLUGIN_INFO
, first_property
,
518 return PURPLE_PLUGIN_INFO(info
);
522 purple_plugin_info_get_id(const PurplePluginInfo
*info
)
524 g_return_val_if_fail(info
!= NULL
, NULL
);
526 return gplugin_plugin_info_get_id(GPLUGIN_PLUGIN_INFO(info
));
530 purple_plugin_info_get_name(const PurplePluginInfo
*info
)
532 g_return_val_if_fail(info
!= NULL
, NULL
);
534 return gplugin_plugin_info_get_name(GPLUGIN_PLUGIN_INFO(info
));
538 purple_plugin_info_get_version(const PurplePluginInfo
*info
)
540 g_return_val_if_fail(info
!= NULL
, NULL
);
542 return gplugin_plugin_info_get_version(GPLUGIN_PLUGIN_INFO(info
));
546 purple_plugin_info_get_category(const PurplePluginInfo
*info
)
548 g_return_val_if_fail(info
!= NULL
, NULL
);
550 return gplugin_plugin_info_get_category(GPLUGIN_PLUGIN_INFO(info
));
554 purple_plugin_info_get_summary(const PurplePluginInfo
*info
)
556 g_return_val_if_fail(info
!= NULL
, NULL
);
558 return gplugin_plugin_info_get_summary(GPLUGIN_PLUGIN_INFO(info
));
562 purple_plugin_info_get_description(const PurplePluginInfo
*info
)
564 g_return_val_if_fail(info
!= NULL
, NULL
);
566 return gplugin_plugin_info_get_description(GPLUGIN_PLUGIN_INFO(info
));
569 const gchar
* const *
570 purple_plugin_info_get_authors(const PurplePluginInfo
*info
)
572 g_return_val_if_fail(info
!= NULL
, NULL
);
574 return gplugin_plugin_info_get_authors(GPLUGIN_PLUGIN_INFO(info
));
578 purple_plugin_info_get_website(const PurplePluginInfo
*info
)
580 g_return_val_if_fail(info
!= NULL
, NULL
);
582 return gplugin_plugin_info_get_website(GPLUGIN_PLUGIN_INFO(info
));
586 purple_plugin_info_get_icon(const PurplePluginInfo
*info
)
588 g_return_val_if_fail(info
!= NULL
, NULL
);
590 return gplugin_plugin_info_get_icon(GPLUGIN_PLUGIN_INFO(info
));
594 purple_plugin_info_get_license_id(const PurplePluginInfo
*info
)
596 g_return_val_if_fail(info
!= NULL
, NULL
);
598 return gplugin_plugin_info_get_license_id(GPLUGIN_PLUGIN_INFO(info
));
602 purple_plugin_info_get_license_text(const PurplePluginInfo
*info
)
604 g_return_val_if_fail(info
!= NULL
, NULL
);
606 return gplugin_plugin_info_get_license_text(GPLUGIN_PLUGIN_INFO(info
));
610 purple_plugin_info_get_license_url(const PurplePluginInfo
*info
)
612 g_return_val_if_fail(info
!= NULL
, NULL
);
614 return gplugin_plugin_info_get_license_url(GPLUGIN_PLUGIN_INFO(info
));
617 const gchar
* const *
618 purple_plugin_info_get_dependencies(const PurplePluginInfo
*info
)
620 g_return_val_if_fail(info
!= NULL
, NULL
);
622 return gplugin_plugin_info_get_dependencies(GPLUGIN_PLUGIN_INFO(info
));
626 purple_plugin_info_get_abi_version(const PurplePluginInfo
*info
)
628 g_return_val_if_fail(info
!= NULL
, 0);
630 return gplugin_plugin_info_get_abi_version(GPLUGIN_PLUGIN_INFO(info
));
633 PurplePluginActionsCb
634 purple_plugin_info_get_actions_cb(PurplePluginInfo
*info
)
636 PurplePluginInfoPrivate
*priv
= NULL
;
638 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
640 priv
= purple_plugin_info_get_instance_private(info
);
641 return priv
->actions_cb
;
645 purple_plugin_info_get_extra_cb(PurplePluginInfo
*info
)
647 PurplePluginInfoPrivate
*priv
= NULL
;
649 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
651 priv
= purple_plugin_info_get_instance_private(info
);
652 return priv
->extra_cb
;
655 PurplePluginPrefFrameCb
656 purple_plugin_info_get_pref_frame_cb(PurplePluginInfo
*info
)
658 PurplePluginInfoPrivate
*priv
= NULL
;
660 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
662 priv
= purple_plugin_info_get_instance_private(info
);
663 return priv
->pref_frame_cb
;
666 PurplePluginPrefRequestCb
667 purple_plugin_info_get_pref_request_cb(PurplePluginInfo
*info
)
669 PurplePluginInfoPrivate
*priv
= NULL
;
671 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
673 priv
= purple_plugin_info_get_instance_private(info
);
674 return priv
->pref_request_cb
;
677 PurplePluginInfoFlags
678 purple_plugin_info_get_flags(PurplePluginInfo
*info
)
680 PurplePluginInfoPrivate
*priv
= NULL
;
682 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), 0);
684 priv
= purple_plugin_info_get_instance_private(info
);
689 purple_plugin_info_get_error(PurplePluginInfo
*info
)
691 PurplePluginInfoPrivate
*priv
= NULL
;
693 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
695 priv
= purple_plugin_info_get_instance_private(info
);
700 purple_plugin_info_set_ui_data(PurplePluginInfo
*info
, gpointer ui_data
)
702 g_return_if_fail(PURPLE_IS_PLUGIN_INFO(info
));
704 info
->ui_data
= ui_data
;
708 purple_plugin_info_get_ui_data(const PurplePluginInfo
*info
)
710 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
712 return info
->ui_data
;
715 /**************************************************************************
717 **************************************************************************/
719 purple_plugin_action_new(const char* label
, PurplePluginActionCb callback
)
721 PurplePluginAction
*action
;
723 g_return_val_if_fail(label
!= NULL
&& callback
!= NULL
, NULL
);
725 action
= g_new0(PurplePluginAction
, 1);
727 action
->label
= g_strdup(label
);
728 action
->callback
= callback
;
734 purple_plugin_action_free(PurplePluginAction
*action
)
736 g_return_if_fail(action
!= NULL
);
738 g_free(action
->label
);
742 static PurplePluginAction
*
743 purple_plugin_action_copy(PurplePluginAction
*action
)
745 g_return_val_if_fail(action
!= NULL
, NULL
);
747 return purple_plugin_action_new(action
->label
, action
->callback
);
751 purple_plugin_action_get_type(void)
753 static GType type
= 0;
755 if (G_UNLIKELY(type
== 0)) {
756 type
= g_boxed_type_register_static("PurplePluginAction",
757 (GBoxedCopyFunc
)purple_plugin_action_copy
,
758 (GBoxedFreeFunc
)purple_plugin_action_free
);
764 /**************************************************************************
766 **************************************************************************/
768 purple_plugins_find_all(void)
770 GList
*ret
= NULL
, *ids
, *l
;
771 GSList
*plugins
, *ll
;
773 ids
= gplugin_manager_list_plugins();
775 for (l
= ids
; l
; l
= l
->next
) {
776 plugins
= gplugin_manager_find_plugins(l
->data
);
778 for (ll
= plugins
; ll
; ll
= ll
->next
) {
779 PurplePlugin
*plugin
= PURPLE_PLUGIN(ll
->data
);
780 if (purple_plugin_get_info(plugin
))
781 ret
= g_list_append(ret
, plugin
);
784 gplugin_manager_free_plugin_list(plugins
);
792 purple_plugins_get_loaded(void)
794 return loaded_plugins
;
798 purple_plugins_add_search_path(const gchar
*path
)
800 gplugin_manager_append_path(path
);
804 purple_plugins_refresh(void)
808 gplugin_manager_refresh();
810 plugins
= purple_plugins_find_all();
811 for (l
= plugins
; l
!= NULL
; l
= l
->next
) {
812 PurplePlugin
*plugin
= PURPLE_PLUGIN(l
->data
);
813 PurplePluginInfo
*info
;
814 PurplePluginInfoPrivate
*priv
;
816 if (purple_plugin_is_loaded(plugin
))
819 info
= purple_plugin_get_info(plugin
);
820 priv
= purple_plugin_info_get_instance_private(info
);
822 if (!priv
->unloaded
&& purple_plugin_info_get_flags(info
) &
823 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
) {
824 purple_debug_info("plugins", "Auto-loading plugin %s\n",
825 purple_plugin_get_filename(plugin
));
826 purple_plugin_load(plugin
, NULL
);
830 g_list_free(plugins
);
834 purple_plugins_find_plugin(const gchar
*id
)
836 PurplePlugin
*plugin
;
838 g_return_val_if_fail(id
!= NULL
&& *id
!= '\0', NULL
);
840 plugin
= gplugin_manager_find_plugin(id
);
845 /* GPlugin refs the plugin object before returning it. This workaround is
846 * to avoid managing the reference counts everywhere in our codebase where
847 * we use plugin instances. A plugin object will exist till the plugins
848 * subsystem is uninitialized. */
849 g_object_unref(plugin
);
855 purple_plugins_find_by_filename(const char *filename
)
859 g_return_val_if_fail(filename
!= NULL
&& *filename
!= '\0', NULL
);
861 plugins
= purple_plugins_find_all();
863 for (l
= plugins
; l
!= NULL
; l
= l
->next
) {
864 PurplePlugin
*plugin
= PURPLE_PLUGIN(l
->data
);
866 if (purple_strequal(purple_plugin_get_filename(plugin
), filename
)) {
867 g_list_free(plugins
);
871 g_list_free(plugins
);
877 purple_plugins_save_loaded(const char *key
)
882 g_return_if_fail(key
!= NULL
&& *key
!= '\0');
884 for (pl
= purple_plugins_get_loaded(); pl
!= NULL
; pl
= pl
->next
) {
885 PurplePlugin
*plugin
= PURPLE_PLUGIN(pl
->data
);
886 PurplePluginInfo
*info
= purple_plugin_get_info(plugin
);
890 if (purple_plugin_info_get_flags(info
) &
891 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
)
894 if (!g_list_find(plugins_to_disable
, plugin
))
895 files
= g_list_append(files
, (gchar
*)purple_plugin_get_filename(plugin
));
898 purple_prefs_set_path_list(key
, files
);
903 purple_plugins_load_saved(const char *key
)
907 g_return_if_fail(key
!= NULL
&& *key
!= '\0');
909 files
= purple_prefs_get_path_list(key
);
911 for (l
= files
; l
; l
= l
->next
)
914 PurplePlugin
*plugin
;
920 plugin
= purple_plugins_find_by_filename(file
);
923 purple_debug_info("plugins", "Loading saved plugin %s\n", file
);
924 purple_plugin_load(plugin
, NULL
);
926 purple_debug_error("plugins", "Unable to find saved plugin %s\n", file
);
935 /**************************************************************************
936 * Plugins Subsystem API
937 **************************************************************************/
939 purple_plugins_get_handle(void)
947 purple_plugins_init(void)
949 void *handle
= purple_plugins_get_handle();
950 const gchar
*search_path
;
952 purple_signal_register(handle
, "plugin-load",
953 purple_marshal_VOID__POINTER
,
954 G_TYPE_NONE
, 1, PURPLE_TYPE_PLUGIN
);
955 purple_signal_register(handle
, "plugin-unload",
956 purple_marshal_VOID__POINTER
,
957 G_TYPE_NONE
, 1, PURPLE_TYPE_PLUGIN
);
961 search_path
= g_getenv("PURPLE_PLUGIN_PATH");
966 paths
= g_strsplit(search_path
, G_SEARCHPATH_SEPARATOR_S
, 0);
967 for (i
= 0; paths
[i
]; ++i
) {
968 purple_plugins_add_search_path(paths
[i
]);
974 gplugin_manager_add_default_paths();
976 if(!g_getenv("PURPLE_PLUGINS_SKIP")) {
977 purple_plugins_add_search_path(PURPLE_LIBDIR
);
979 purple_debug_info("plugins", "PURPLE_PLUGINS_SKIP environment variable set, skipping normal plugin paths");
982 g_signal_connect(gplugin_manager_get_instance(), "loading-plugin",
983 G_CALLBACK(plugin_loading_cb
), NULL
);
984 g_signal_connect(gplugin_manager_get_instance(), "loaded-plugin",
985 G_CALLBACK(plugin_loaded_cb
), NULL
);
986 g_signal_connect(gplugin_manager_get_instance(), "unloading-plugin",
987 G_CALLBACK(plugin_unloading_cb
), NULL
);
988 g_signal_connect(gplugin_manager_get_instance(), "unloaded-plugin",
989 G_CALLBACK(plugin_unloaded_cb
), NULL
);
991 purple_plugins_refresh();
995 purple_plugins_uninit(void)
997 void *handle
= purple_plugins_get_handle();
999 purple_debug_info("plugins", "Unloading all plugins\n");
1000 while (loaded_plugins
!= NULL
)
1001 purple_plugin_unload(loaded_plugins
->data
, NULL
);
1003 purple_signals_disconnect_by_handle(handle
);
1004 purple_signals_unregister_by_instance(handle
);