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
26 #include "dbus-maybe.h"
30 #define PURPLE_PLUGIN_INFO_GET_PRIVATE(obj) \
31 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PLUGIN_INFO, PurplePluginInfoPrivate))
33 typedef struct _PurplePluginInfoPrivate PurplePluginInfoPrivate
;
35 /**************************************************************************
36 * Plugin info private data
37 **************************************************************************/
38 struct _PurplePluginInfoPrivate
{
39 char *ui_requirement
; /* ID of UI that is required to load the plugin */
40 char *error
; /* Why a plugin is not loadable */
42 PurplePluginInfoFlags flags
; /* Flags for the plugin */
44 /* Callback that returns a list of actions the plugin can perform */
45 PurplePluginActionsCb actions_cb
;
47 /* Callback that returns extra information about a plugin */
48 PurplePluginExtraCb extra_cb
;
50 /* Callback that returns a preferences frame for a plugin */
51 PurplePluginPrefFrameCb pref_frame_cb
;
53 /* Callback that returns a preferences request handle for a plugin */
54 PurplePluginPrefRequestCb pref_request_cb
;
56 /* TRUE if a plugin has been unloaded at least once. Auto-load
57 * plugins that have been unloaded once will not be auto-loaded again. */
73 static GObjectClass
*parent_class
;
75 /**************************************************************************
77 **************************************************************************/
79 static GList
*loaded_plugins
= NULL
;
80 static GList
*plugins_to_disable
= NULL
;
83 /**************************************************************************
85 **************************************************************************/
88 plugin_loading_cb(GObject
*manager
, PurplePlugin
*plugin
, GError
**error
,
91 PurplePluginInfo
*info
;
92 PurplePluginInfoPrivate
*priv
;
94 g_return_val_if_fail(PURPLE_IS_PLUGIN(plugin
), FALSE
);
96 info
= purple_plugin_get_info(plugin
);
98 return TRUE
; /* a GPlugin internal plugin */
100 priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
103 purple_debug_error("plugins", "Failed to load plugin %s: %s",
104 purple_plugin_get_filename(plugin
), priv
->error
);
106 g_set_error(error
, PURPLE_PLUGINS_DOMAIN
, 0,
107 "Plugin is not loadable: %s", priv
->error
);
116 plugin_loaded_cb(GObject
*manager
, PurplePlugin
*plugin
)
118 PurplePluginInfo
*info
;
120 g_return_if_fail(PURPLE_IS_PLUGIN(plugin
));
122 info
= purple_plugin_get_info(plugin
);
124 return; /* a GPlugin internal plugin */
126 loaded_plugins
= g_list_prepend(loaded_plugins
, plugin
);
128 purple_debug_info("plugins", "Loaded plugin %s\n",
129 purple_plugin_get_filename(plugin
));
131 purple_signal_emit(purple_plugins_get_handle(), "plugin-load", plugin
);
135 plugin_unloading_cb(GObject
*manager
, PurplePlugin
*plugin
, GError
**error
,
138 PurplePluginInfo
*info
;
140 g_return_val_if_fail(PURPLE_IS_PLUGIN(plugin
), FALSE
);
142 info
= purple_plugin_get_info(plugin
);
144 purple_debug_info("plugins", "Unloading plugin %s\n",
145 purple_plugin_get_filename(plugin
));
152 plugin_unloaded_cb(GObject
*manager
, PurplePlugin
*plugin
)
154 PurplePluginInfo
*info
;
155 PurplePluginInfoPrivate
*priv
;
157 g_return_if_fail(PURPLE_IS_PLUGIN(plugin
));
159 info
= purple_plugin_get_info(plugin
);
161 return; /* a GPlugin internal plugin */
163 priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
165 /* cancel any pending dialogs the plugin has */
166 purple_request_close_with_handle(plugin
);
167 purple_notify_close_with_handle(plugin
);
169 purple_signals_disconnect_by_handle(plugin
);
170 purple_signals_unregister_by_instance(plugin
);
172 priv
->unloaded
= TRUE
;
174 loaded_plugins
= g_list_remove(loaded_plugins
, plugin
);
175 plugins_to_disable
= g_list_remove(plugins_to_disable
, plugin
);
177 purple_signal_emit(purple_plugins_get_handle(), "plugin-unload", plugin
);
179 purple_prefs_disconnect_by_handle(plugin
);
181 #endif /* PURPLE_PLUGINS */
184 purple_plugin_load(PurplePlugin
*plugin
, GError
**error
)
186 #ifdef PURPLE_PLUGINS
189 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
191 if (purple_plugin_is_loaded(plugin
))
194 if (!gplugin_manager_load_plugin(plugin
, &err
)) {
195 purple_debug_error("plugins", "Failed to load plugin %s: %s",
196 purple_plugin_get_filename(plugin
),
197 (err
? err
->message
: "Unknown reason"));
200 *error
= g_error_copy(err
);
209 g_set_error(error
, PURPLE_PLUGINS_DOMAIN
, 0, "Plugin support is disabled.");
211 #endif /* PURPLE_PLUGINS */
215 purple_plugin_unload(PurplePlugin
*plugin
, GError
**error
)
217 #ifdef PURPLE_PLUGINS
220 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
222 if (!purple_plugin_is_loaded(plugin
))
225 if (!gplugin_manager_unload_plugin(plugin
, &err
)) {
226 purple_debug_error("plugins", "Failed to unload plugin %s: %s",
227 purple_plugin_get_filename(plugin
),
228 (err
? err
->message
: "Unknown reason"));
231 *error
= g_error_copy(err
);
240 g_set_error(error
, PURPLE_PLUGINS_DOMAIN
, 0, "Plugin support is disabled.");
242 #endif /* PURPLE_PLUGINS */
246 purple_plugin_is_loaded(const PurplePlugin
*plugin
)
248 #ifdef PURPLE_PLUGINS
249 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
251 return (gplugin_plugin_get_state(plugin
) == GPLUGIN_PLUGIN_STATE_LOADED
);
259 purple_plugin_get_filename(const PurplePlugin
*plugin
)
261 #ifdef PURPLE_PLUGINS
262 g_return_val_if_fail(plugin
!= NULL
, NULL
);
264 return gplugin_plugin_get_filename(plugin
);
272 purple_plugin_get_info(const PurplePlugin
*plugin
)
274 #ifdef PURPLE_PLUGINS
275 GPluginPluginInfo
*info
;
277 g_return_val_if_fail(plugin
!= NULL
, NULL
);
279 info
= gplugin_plugin_get_info(plugin
);
281 /* GPlugin refs the plugin info object before returning it. This workaround
282 * is to avoid managing the reference counts everywhere in our codebase
283 * where we use the plugin info. The plugin info instance is guaranteed to
284 * exist as long as the plugin exists. */
285 g_object_unref(info
);
287 if (PURPLE_IS_PLUGIN_INFO(info
))
288 return PURPLE_PLUGIN_INFO(info
);
297 purple_plugin_disable(PurplePlugin
*plugin
)
299 #ifdef PURPLE_PLUGINS
300 g_return_if_fail(plugin
!= NULL
);
302 if (!g_list_find(plugins_to_disable
, plugin
))
303 plugins_to_disable
= g_list_prepend(plugins_to_disable
, plugin
);
308 purple_plugin_register_type(PurplePlugin
*plugin
, GType parent
,
309 const gchar
*name
, const GTypeInfo
*info
,
312 #ifdef PURPLE_PLUGINS
313 g_return_val_if_fail(GPLUGIN_IS_NATIVE_PLUGIN(plugin
), G_TYPE_INVALID
);
315 return gplugin_native_plugin_register_type(GPLUGIN_NATIVE_PLUGIN(plugin
),
316 parent
, name
, info
, flags
);
319 return G_TYPE_INVALID
;
324 purple_plugin_add_interface(PurplePlugin
*plugin
, GType instance_type
,
325 GType interface_type
,
326 const GInterfaceInfo
*interface_info
)
328 #ifdef PURPLE_PLUGINS
329 g_return_if_fail(GPLUGIN_IS_NATIVE_PLUGIN(plugin
));
331 gplugin_native_plugin_add_interface(GPLUGIN_NATIVE_PLUGIN(plugin
),
332 instance_type
, interface_type
,
338 purple_plugin_is_internal(const PurplePlugin
*plugin
)
340 PurplePluginInfo
*info
;
342 g_return_val_if_fail(plugin
!= NULL
, FALSE
);
344 info
= purple_plugin_get_info(plugin
);
348 return (purple_plugin_info_get_flags(info
) &
349 PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
);
353 purple_plugin_get_dependent_plugins(const PurplePlugin
*plugin
)
355 #warning TODO: Implement this when GPlugin can return dependent plugins.
357 #ifdef PURPLE_PLUGINS
364 /**************************************************************************
365 * GObject code for PurplePluginInfo
366 **************************************************************************/
367 /* GObject initialization function */
369 purple_plugin_info_init(GTypeInstance
*instance
, gpointer klass
)
371 PURPLE_DBUS_REGISTER_POINTER(PURPLE_PLUGIN_INFO(instance
), PurplePluginInfo
);
374 /* Set method for GObject properties */
376 purple_plugin_info_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
379 PurplePluginInfo
*info
= PURPLE_PLUGIN_INFO(obj
);
380 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
383 case PROP_UI_REQUIREMENT
:
384 priv
->ui_requirement
= g_strdup(g_value_get_string(value
));
386 case PROP_ACTIONS_CB
:
387 priv
->actions_cb
= g_value_get_pointer(value
);
390 priv
->extra_cb
= g_value_get_pointer(value
);
392 case PROP_PREF_FRAME_CB
:
393 priv
->pref_frame_cb
= g_value_get_pointer(value
);
395 case PROP_PREF_REQUEST_CB
:
396 priv
->pref_request_cb
= g_value_get_pointer(value
);
399 priv
->flags
= g_value_get_flags(value
);
402 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
407 /* Get method for GObject properties */
409 purple_plugin_info_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
412 PurplePluginInfo
*info
= PURPLE_PLUGIN_INFO(obj
);
415 case PROP_ACTIONS_CB
:
416 g_value_set_pointer(value
,
417 purple_plugin_info_get_actions_cb(info
));
420 g_value_set_pointer(value
,
421 purple_plugin_info_get_extra_cb(info
));
423 case PROP_PREF_FRAME_CB
:
424 g_value_set_pointer(value
,
425 purple_plugin_info_get_pref_frame_cb(info
));
427 case PROP_PREF_REQUEST_CB
:
428 g_value_set_pointer(value
,
429 purple_plugin_info_get_pref_request_cb(info
));
432 g_value_set_flags(value
, purple_plugin_info_get_flags(info
));
435 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
440 /* Called when done constructing */
442 purple_plugin_info_constructed(GObject
*object
)
444 PurplePluginInfo
*info
= PURPLE_PLUGIN_INFO(object
);
445 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
446 const char *id
= purple_plugin_info_get_id(info
);
449 parent_class
->constructed(object
);
451 if (id
== NULL
|| *id
== '\0')
452 priv
->error
= g_strdup(_("This plugin has not defined an ID."));
454 if (priv
->ui_requirement
&& !purple_strequal(priv
->ui_requirement
, purple_core_get_ui()))
456 priv
->error
= g_strdup_printf(_("You are using %s, but this plugin requires %s."),
457 purple_core_get_ui(), priv
->ui_requirement
);
458 purple_debug_error("plugins", "%s is not loadable: The UI requirement is not met. (%s)\n",
462 version
= purple_plugin_info_get_abi_version(info
);
463 if (PURPLE_PLUGIN_ABI_MAJOR_VERSION(version
) != PURPLE_MAJOR_VERSION
||
464 PURPLE_PLUGIN_ABI_MINOR_VERSION(version
) > PURPLE_MINOR_VERSION
)
466 priv
->error
= g_strdup_printf(_("Your libpurple version is %d.%d.x (need %d.%d.x)"),
467 PURPLE_MAJOR_VERSION
, PURPLE_MINOR_VERSION
,
468 PURPLE_PLUGIN_ABI_MAJOR_VERSION(version
),
469 PURPLE_PLUGIN_ABI_MINOR_VERSION(version
));
470 purple_debug_error("plugins", "%s is not loadable: libpurple version is %d.%d.x (need %d.%d.x)\n",
471 id
, PURPLE_MAJOR_VERSION
, PURPLE_MINOR_VERSION
,
472 PURPLE_PLUGIN_ABI_MAJOR_VERSION(version
),
473 PURPLE_PLUGIN_ABI_MINOR_VERSION(version
));
477 /* GObject finalize function */
479 purple_plugin_info_finalize(GObject
*object
)
481 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(object
);
483 g_free(priv
->ui_requirement
);
486 PURPLE_DBUS_UNREGISTER_POINTER(object
);
488 parent_class
->finalize(object
);
491 /* Class initializer function */
492 static void purple_plugin_info_class_init(PurplePluginInfoClass
*klass
)
494 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
496 parent_class
= g_type_class_peek_parent(klass
);
498 g_type_class_add_private(klass
, sizeof(PurplePluginInfoPrivate
));
500 obj_class
->constructed
= purple_plugin_info_constructed
;
501 obj_class
->finalize
= purple_plugin_info_finalize
;
503 /* Setup properties */
504 obj_class
->get_property
= purple_plugin_info_get_property
;
505 obj_class
->set_property
= purple_plugin_info_set_property
;
507 g_object_class_install_property(obj_class
, PROP_UI_REQUIREMENT
,
508 g_param_spec_string("ui-requirement",
510 "ID of UI that is required by this plugin", NULL
,
511 G_PARAM_WRITABLE
| G_PARAM_STATIC_STRINGS
));
513 g_object_class_install_property(obj_class
, PROP_ACTIONS_CB
,
514 g_param_spec_pointer("actions-cb",
516 "Callback that returns list of plugin's actions",
517 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
518 G_PARAM_STATIC_STRINGS
));
520 g_object_class_install_property(obj_class
, PROP_EXTRA_CB
,
521 g_param_spec_pointer("extra-cb",
522 "Extra info callback",
523 "Callback that returns extra info about the plugin",
524 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
525 G_PARAM_STATIC_STRINGS
));
527 g_object_class_install_property(obj_class
, PROP_PREF_FRAME_CB
,
528 g_param_spec_pointer("pref-frame-cb",
529 "Preferences frame callback",
530 "The callback that returns the preferences frame",
531 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
532 G_PARAM_STATIC_STRINGS
));
534 g_object_class_install_property(obj_class
, PROP_PREF_REQUEST_CB
,
535 g_param_spec_pointer("pref-request-cb",
536 "Preferences request callback",
537 "Callback that returns preferences request handle",
538 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
539 G_PARAM_STATIC_STRINGS
));
541 g_object_class_install_property(obj_class
, PROP_FLAGS
,
542 g_param_spec_flags("flags",
544 "The flags for the plugin",
545 PURPLE_TYPE_PLUGIN_INFO_FLAGS
, 0,
546 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
547 G_PARAM_STATIC_STRINGS
));
550 /**************************************************************************
552 **************************************************************************/
554 purple_plugin_info_get_type(void)
556 static GType type
= 0;
558 if (G_UNLIKELY(type
== 0)) {
559 static const GTypeInfo info
= {
560 .class_size
= sizeof(PurplePluginInfoClass
),
561 .class_init
= (GClassInitFunc
)purple_plugin_info_class_init
,
562 .instance_size
= sizeof(PurplePluginInfo
),
563 .instance_init
= (GInstanceInitFunc
)purple_plugin_info_init
,
566 type
= g_type_register_static(
567 #ifdef PURPLE_PLUGINS
568 GPLUGIN_TYPE_PLUGIN_INFO
,
572 "PurplePluginInfo", &info
, 0);
579 purple_plugin_info_new(const char *first_property
, ...)
584 /* at least ID is required */
588 va_start(var_args
, first_property
);
589 info
= g_object_new_valist(PURPLE_TYPE_PLUGIN_INFO
, first_property
,
593 return PURPLE_PLUGIN_INFO(info
);
597 purple_plugin_info_get_id(const PurplePluginInfo
*info
)
599 #ifdef PURPLE_PLUGINS
600 g_return_val_if_fail(info
!= NULL
, NULL
);
602 return gplugin_plugin_info_get_id(GPLUGIN_PLUGIN_INFO(info
));
610 purple_plugin_info_get_name(const PurplePluginInfo
*info
)
612 #ifdef PURPLE_PLUGINS
613 g_return_val_if_fail(info
!= NULL
, NULL
);
615 return gplugin_plugin_info_get_name(GPLUGIN_PLUGIN_INFO(info
));
623 purple_plugin_info_get_version(const PurplePluginInfo
*info
)
625 #ifdef PURPLE_PLUGINS
626 g_return_val_if_fail(info
!= NULL
, NULL
);
628 return gplugin_plugin_info_get_version(GPLUGIN_PLUGIN_INFO(info
));
636 purple_plugin_info_get_category(const PurplePluginInfo
*info
)
638 #ifdef PURPLE_PLUGINS
639 g_return_val_if_fail(info
!= NULL
, NULL
);
641 return gplugin_plugin_info_get_category(GPLUGIN_PLUGIN_INFO(info
));
649 purple_plugin_info_get_summary(const PurplePluginInfo
*info
)
651 #ifdef PURPLE_PLUGINS
652 g_return_val_if_fail(info
!= NULL
, NULL
);
654 return gplugin_plugin_info_get_summary(GPLUGIN_PLUGIN_INFO(info
));
662 purple_plugin_info_get_description(const PurplePluginInfo
*info
)
664 #ifdef PURPLE_PLUGINS
665 g_return_val_if_fail(info
!= NULL
, NULL
);
667 return gplugin_plugin_info_get_description(GPLUGIN_PLUGIN_INFO(info
));
674 const gchar
* const *
675 purple_plugin_info_get_authors(const PurplePluginInfo
*info
)
677 #ifdef PURPLE_PLUGINS
678 g_return_val_if_fail(info
!= NULL
, NULL
);
680 return gplugin_plugin_info_get_authors(GPLUGIN_PLUGIN_INFO(info
));
688 purple_plugin_info_get_website(const PurplePluginInfo
*info
)
690 #ifdef PURPLE_PLUGINS
691 g_return_val_if_fail(info
!= NULL
, NULL
);
693 return gplugin_plugin_info_get_website(GPLUGIN_PLUGIN_INFO(info
));
701 purple_plugin_info_get_icon(const PurplePluginInfo
*info
)
703 #ifdef PURPLE_PLUGINS
704 g_return_val_if_fail(info
!= NULL
, NULL
);
706 return gplugin_plugin_info_get_icon(GPLUGIN_PLUGIN_INFO(info
));
714 purple_plugin_info_get_license_id(const PurplePluginInfo
*info
)
716 #ifdef PURPLE_PLUGINS
717 g_return_val_if_fail(info
!= NULL
, NULL
);
719 return gplugin_plugin_info_get_license_id(GPLUGIN_PLUGIN_INFO(info
));
727 purple_plugin_info_get_license_text(const PurplePluginInfo
*info
)
729 #ifdef PURPLE_PLUGINS
730 g_return_val_if_fail(info
!= NULL
, NULL
);
732 return gplugin_plugin_info_get_license_text(GPLUGIN_PLUGIN_INFO(info
));
740 purple_plugin_info_get_license_url(const PurplePluginInfo
*info
)
742 #ifdef PURPLE_PLUGINS
743 g_return_val_if_fail(info
!= NULL
, NULL
);
745 return gplugin_plugin_info_get_license_url(GPLUGIN_PLUGIN_INFO(info
));
752 const gchar
* const *
753 purple_plugin_info_get_dependencies(const PurplePluginInfo
*info
)
755 #ifdef PURPLE_PLUGINS
756 g_return_val_if_fail(info
!= NULL
, NULL
);
758 return gplugin_plugin_info_get_dependencies(GPLUGIN_PLUGIN_INFO(info
));
766 purple_plugin_info_get_abi_version(const PurplePluginInfo
*info
)
768 #ifdef PURPLE_PLUGINS
769 g_return_val_if_fail(info
!= NULL
, 0);
771 return gplugin_plugin_info_get_abi_version(GPLUGIN_PLUGIN_INFO(info
));
778 PurplePluginActionsCb
779 purple_plugin_info_get_actions_cb(const PurplePluginInfo
*info
)
781 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
783 g_return_val_if_fail(priv
!= NULL
, NULL
);
785 return priv
->actions_cb
;
789 purple_plugin_info_get_extra_cb(const PurplePluginInfo
*info
)
791 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
793 g_return_val_if_fail(priv
!= NULL
, NULL
);
795 return priv
->extra_cb
;
798 PurplePluginPrefFrameCb
799 purple_plugin_info_get_pref_frame_cb(const PurplePluginInfo
*info
)
801 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
803 g_return_val_if_fail(priv
!= NULL
, NULL
);
805 return priv
->pref_frame_cb
;
808 PurplePluginPrefRequestCb
809 purple_plugin_info_get_pref_request_cb(const PurplePluginInfo
*info
)
811 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
813 g_return_val_if_fail(priv
!= NULL
, NULL
);
815 return priv
->pref_request_cb
;
818 PurplePluginInfoFlags
819 purple_plugin_info_get_flags(const PurplePluginInfo
*info
)
821 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
823 g_return_val_if_fail(priv
!= NULL
, 0);
829 purple_plugin_info_get_error(const PurplePluginInfo
*info
)
831 PurplePluginInfoPrivate
*priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
833 g_return_val_if_fail(priv
!= NULL
, NULL
);
839 purple_plugin_info_set_ui_data(PurplePluginInfo
*info
, gpointer ui_data
)
841 g_return_if_fail(PURPLE_IS_PLUGIN_INFO(info
));
843 info
->ui_data
= ui_data
;
847 purple_plugin_info_get_ui_data(const PurplePluginInfo
*info
)
849 g_return_val_if_fail(PURPLE_IS_PLUGIN_INFO(info
), NULL
);
851 return info
->ui_data
;
854 /**************************************************************************
856 **************************************************************************/
858 purple_plugin_action_new(const char* label
, PurplePluginActionCb callback
)
860 PurplePluginAction
*action
;
862 g_return_val_if_fail(label
!= NULL
&& callback
!= NULL
, NULL
);
864 action
= g_new0(PurplePluginAction
, 1);
866 action
->label
= g_strdup(label
);
867 action
->callback
= callback
;
873 purple_plugin_action_free(PurplePluginAction
*action
)
875 g_return_if_fail(action
!= NULL
);
877 g_free(action
->label
);
881 static PurplePluginAction
*
882 purple_plugin_action_copy(PurplePluginAction
*action
)
884 g_return_val_if_fail(action
!= NULL
, NULL
);
886 return purple_plugin_action_new(action
->label
, action
->callback
);
890 purple_plugin_action_get_type(void)
892 static GType type
= 0;
894 if (G_UNLIKELY(type
== 0)) {
895 type
= g_boxed_type_register_static("PurplePluginAction",
896 (GBoxedCopyFunc
)purple_plugin_action_copy
,
897 (GBoxedFreeFunc
)purple_plugin_action_free
);
903 /**************************************************************************
905 **************************************************************************/
907 purple_plugins_find_all(void)
909 #ifdef PURPLE_PLUGINS
910 GList
*ret
= NULL
, *ids
, *l
;
911 GSList
*plugins
, *ll
;
913 ids
= gplugin_manager_list_plugins();
915 for (l
= ids
; l
; l
= l
->next
) {
916 plugins
= gplugin_manager_find_plugins(l
->data
);
918 for (ll
= plugins
; ll
; ll
= ll
->next
) {
919 PurplePlugin
*plugin
= PURPLE_PLUGIN(ll
->data
);
920 if (purple_plugin_get_info(plugin
))
921 ret
= g_list_append(ret
, plugin
);
924 gplugin_manager_free_plugin_list(plugins
);
936 purple_plugins_get_loaded(void)
938 #ifdef PURPLE_PLUGINS
939 return loaded_plugins
;
946 purple_plugins_add_search_path(const gchar
*path
)
948 #ifdef PURPLE_PLUGINS
949 gplugin_manager_append_path(path
);
954 purple_plugins_refresh(void)
956 #ifdef PURPLE_PLUGINS
959 gplugin_manager_refresh();
961 plugins
= purple_plugins_find_all();
962 for (l
= plugins
; l
!= NULL
; l
= l
->next
) {
963 PurplePlugin
*plugin
= PURPLE_PLUGIN(l
->data
);
964 PurplePluginInfo
*info
;
965 PurplePluginInfoPrivate
*priv
;
967 if (purple_plugin_is_loaded(plugin
))
970 info
= purple_plugin_get_info(plugin
);
971 priv
= PURPLE_PLUGIN_INFO_GET_PRIVATE(info
);
973 if (!priv
->unloaded
&& purple_plugin_info_get_flags(info
) &
974 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
) {
975 purple_debug_info("plugins", "Auto-loading plugin %s\n",
976 purple_plugin_get_filename(plugin
));
977 purple_plugin_load(plugin
, NULL
);
981 g_list_free(plugins
);
986 purple_plugins_find_plugin(const gchar
*id
)
988 #ifdef PURPLE_PLUGINS
989 PurplePlugin
*plugin
;
991 g_return_val_if_fail(id
!= NULL
&& *id
!= '\0', NULL
);
993 plugin
= gplugin_manager_find_plugin(id
);
998 /* GPlugin refs the plugin object before returning it. This workaround is
999 * to avoid managing the reference counts everywhere in our codebase where
1000 * we use plugin instances. A plugin object will exist till the plugins
1001 * subsystem is uninitialized. */
1002 g_object_unref(plugin
);
1012 purple_plugins_find_by_filename(const char *filename
)
1016 g_return_val_if_fail(filename
!= NULL
&& *filename
!= '\0', NULL
);
1018 plugins
= purple_plugins_find_all();
1020 for (l
= plugins
; l
!= NULL
; l
= l
->next
) {
1021 PurplePlugin
*plugin
= PURPLE_PLUGIN(l
->data
);
1023 if (purple_strequal(purple_plugin_get_filename(plugin
), filename
)) {
1024 g_list_free(plugins
);
1028 g_list_free(plugins
);
1034 purple_plugins_save_loaded(const char *key
)
1036 #ifdef PURPLE_PLUGINS
1038 GList
*files
= NULL
;
1040 g_return_if_fail(key
!= NULL
&& *key
!= '\0');
1042 for (pl
= purple_plugins_get_loaded(); pl
!= NULL
; pl
= pl
->next
) {
1043 PurplePlugin
*plugin
= PURPLE_PLUGIN(pl
->data
);
1044 PurplePluginInfo
*info
= purple_plugin_get_info(plugin
);
1048 if (purple_plugin_info_get_flags(info
) &
1049 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
)
1052 if (!g_list_find(plugins_to_disable
, plugin
))
1053 files
= g_list_append(files
, (gchar
*)purple_plugin_get_filename(plugin
));
1056 purple_prefs_set_path_list(key
, files
);
1062 purple_plugins_load_saved(const char *key
)
1064 #ifdef PURPLE_PLUGINS
1067 g_return_if_fail(key
!= NULL
&& *key
!= '\0');
1069 files
= purple_prefs_get_path_list(key
);
1071 for (l
= files
; l
; l
= l
->next
)
1074 PurplePlugin
*plugin
;
1076 if (l
->data
== NULL
)
1080 plugin
= purple_plugins_find_by_filename(file
);
1083 purple_debug_info("plugins", "Loading saved plugin %s\n", file
);
1084 purple_plugin_load(plugin
, NULL
);
1086 purple_debug_error("plugins", "Unable to find saved plugin %s\n", file
);
1093 #endif /* PURPLE_PLUGINS */
1096 /**************************************************************************
1097 * Plugins Subsystem API
1098 **************************************************************************/
1100 purple_plugins_get_handle(void)
1108 purple_plugins_init(void)
1110 void *handle
= purple_plugins_get_handle();
1111 #ifdef PURPLE_PLUGINS
1112 const gchar
*search_path
;
1115 purple_signal_register(handle
, "plugin-load",
1116 purple_marshal_VOID__POINTER
,
1117 G_TYPE_NONE
, 1, PURPLE_TYPE_PLUGIN
);
1118 purple_signal_register(handle
, "plugin-unload",
1119 purple_marshal_VOID__POINTER
,
1120 G_TYPE_NONE
, 1, PURPLE_TYPE_PLUGIN
);
1122 #ifdef PURPLE_PLUGINS
1125 search_path
= g_getenv("PURPLE_PLUGIN_PATH");
1130 paths
= g_strsplit(search_path
, G_SEARCHPATH_SEPARATOR_S
, 0);
1131 for (i
= 0; paths
[i
]; ++i
) {
1132 purple_plugins_add_search_path(paths
[i
]);
1138 gplugin_manager_add_default_paths();
1140 purple_plugins_add_search_path(PURPLE_LIBDIR
);
1142 g_signal_connect(gplugin_manager_get_instance(), "loading-plugin",
1143 G_CALLBACK(plugin_loading_cb
), NULL
);
1144 g_signal_connect(gplugin_manager_get_instance(), "loaded-plugin",
1145 G_CALLBACK(plugin_loaded_cb
), NULL
);
1146 g_signal_connect(gplugin_manager_get_instance(), "unloading-plugin",
1147 G_CALLBACK(plugin_unloading_cb
), NULL
);
1148 g_signal_connect(gplugin_manager_get_instance(), "unloaded-plugin",
1149 G_CALLBACK(plugin_unloaded_cb
), NULL
);
1151 purple_plugins_refresh();
1156 purple_plugins_uninit(void)
1158 void *handle
= purple_plugins_get_handle();
1160 #ifdef PURPLE_PLUGINS
1161 purple_debug_info("plugins", "Unloading all plugins\n");
1162 while (loaded_plugins
!= NULL
)
1163 purple_plugin_unload(loaded_plugins
->data
, NULL
);
1166 purple_signals_disconnect_by_handle(handle
);
1167 purple_signals_unregister_by_instance(handle
);
1169 #ifdef PURPLE_PLUGINS