| 56 GaimValue **params; |
56 GaimValue **params; |
| 57 GaimValue *ret_value; |
57 GaimValue *ret_value; |
| 58 |
58 |
| 59 } GaimPluginIpcCommand; |
59 } GaimPluginIpcCommand; |
| 60 |
60 |
| |
61 static GList *search_paths = NULL; |
| |
62 static GList *plugins = NULL; |
| |
63 static GList *load_queue = NULL; |
| 61 static GList *loaded_plugins = NULL; |
64 static GList *loaded_plugins = NULL; |
| 62 static GList *plugins = NULL; |
|
| 63 static GList *plugin_loaders = NULL; |
65 static GList *plugin_loaders = NULL; |
| 64 static GList *protocol_plugins = NULL; |
66 static GList *protocol_plugins = NULL; |
| 65 static GList *load_queue = NULL; |
|
| 66 |
|
| 67 static size_t search_path_count = 0; |
|
| 68 static char **search_paths = NULL; |
|
| 69 |
67 |
| 70 static void (*probe_cb)(void *) = NULL; |
68 static void (*probe_cb)(void *) = NULL; |
| 71 static void *probe_cb_data = NULL; |
69 static void *probe_cb_data = NULL; |
| 72 static void (*load_cb)(GaimPlugin *, void *) = NULL; |
70 static void (*load_cb)(GaimPlugin *, void *) = NULL; |
| 73 static void *load_cb_data = NULL; |
71 static void *load_cb_data = NULL; |
| 96 len = strlen(filename) - extlen; |
95 len = strlen(filename) - extlen; |
| 97 |
96 |
| 98 if (len < 0) |
97 if (len < 0) |
| 99 return 0; |
98 return 0; |
| 100 |
99 |
| 101 return (!strncmp(filename + len, ext, extlen)); |
100 return (strncmp(filename + len, ext, extlen) == 0); |
| 102 } |
101 } |
| 103 |
102 |
| 104 static gboolean |
103 static gboolean |
| 105 loader_supports_file(GaimPlugin *loader, const char *filename) |
104 loader_supports_file(GaimPlugin *loader, const char *filename) |
| 106 { |
105 { |
| 107 GList *exts; |
106 GList *exts; |
| 108 |
107 |
| 109 for (exts = GAIM_PLUGIN_LOADER_INFO(loader)->exts; exts != NULL; exts = exts->next) { |
108 for (exts = GAIM_PLUGIN_LOADER_INFO(loader)->exts; exts != NULL; exts = exts->next) { |
| 110 if (is_so_file(filename, (char *)exts->data)) { |
109 if (has_file_extension(filename, (char *)exts->data)) { |
| 111 return TRUE; |
110 return TRUE; |
| 112 } |
111 } |
| 113 } |
112 } |
| 114 |
113 |
| 115 return FALSE; |
114 return FALSE; |
| 139 return NULL; |
138 return NULL; |
| 140 } |
139 } |
| 141 |
140 |
| 142 #endif /* GAIM_PLUGINS */ |
141 #endif /* GAIM_PLUGINS */ |
| 143 |
142 |
| |
143 /** |
| |
144 * Negative if a before b, 0 if equal, positive if a after b. |
| |
145 */ |
| 144 static gint |
146 static gint |
| 145 compare_prpl(GaimPlugin *a, GaimPlugin *b) |
147 compare_prpl(GaimPlugin *a, GaimPlugin *b) |
| 146 { |
148 { |
| 147 /* neg if a before b, 0 if equal, pos if a after b */ |
|
| 148 if(GAIM_IS_PROTOCOL_PLUGIN(a)) { |
149 if(GAIM_IS_PROTOCOL_PLUGIN(a)) { |
| 149 if(GAIM_IS_PROTOCOL_PLUGIN(b)) |
150 if(GAIM_IS_PROTOCOL_PLUGIN(b)) |
| 150 return strcmp(a->info->name, b->info->name); |
151 return strcmp(a->info->name, b->info->name); |
| 151 else |
152 else |
| 152 return -1; |
153 return -1; |
| 184 g_return_val_if_fail(filename != NULL, NULL); |
185 g_return_val_if_fail(filename != NULL, NULL); |
| 185 |
186 |
| 186 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) |
187 if (!g_file_test(filename, G_FILE_TEST_EXISTS)) |
| 187 return NULL; |
188 return NULL; |
| 188 |
189 |
| |
190 /* If this plugin has already been probed then exit */ |
| 189 plugin = gaim_plugins_find_with_filename(filename); |
191 plugin = gaim_plugins_find_with_filename(filename); |
| 190 |
|
| 191 if (plugin != NULL) |
192 if (plugin != NULL) |
| 192 return plugin; |
193 return plugin; |
| 193 |
194 |
| 194 plugin = gaim_plugin_new(is_so_file(filename, PLUGIN_EXT), filename); |
195 plugin = gaim_plugin_new(has_file_extension(filename, PLUGIN_EXT), filename); |
| 195 |
196 |
| 196 if (plugin->native_plugin) { |
197 if (plugin->native_plugin) { |
| 197 const char *error; |
198 const char *error; |
| 198 plugin->handle = g_module_open(filename, 0); |
199 plugin->handle = g_module_open(filename, 0); |
| 199 |
200 |
| 200 if (plugin->handle == NULL) { |
201 if (plugin->handle == NULL) |
| |
202 { |
| 201 error = g_module_error(); |
203 error = g_module_error(); |
| 202 gaim_debug(GAIM_DEBUG_ERROR, "plugins", "%s is unloadable: %s\n", |
204 gaim_debug_error("plugins", "%s is unloadable: %s\n", |
| 203 plugin->path, error ? error : "Unknown error."); |
205 plugin->path, error ? error : "Unknown error."); |
| 204 |
206 |
| 205 gaim_plugin_destroy(plugin); |
207 gaim_plugin_destroy(plugin); |
| 206 |
208 |
| 207 return NULL; |
209 return NULL; |
| 208 } |
210 } |
| 209 |
211 |
| 210 if (!g_module_symbol(plugin->handle, "gaim_init_plugin", |
212 if (!g_module_symbol(plugin->handle, "gaim_init_plugin", |
| 211 &unpunned)) { |
213 &unpunned)) |
| |
214 { |
| 212 g_module_close(plugin->handle); |
215 g_module_close(plugin->handle); |
| 213 plugin->handle = NULL; |
216 plugin->handle = NULL; |
| 214 |
217 |
| 215 error = g_module_error(); |
218 error = g_module_error(); |
| 216 gaim_debug(GAIM_DEBUG_ERROR, "plugins", "%s is unloadable: %s\n", |
219 gaim_debug_error("plugins", "%s is unloadable: %s\n", |
| 217 plugin->path, error ? error : "Unknown error."); |
220 plugin->path, error ? error : "Unknown error."); |
| 218 |
221 |
| 219 gaim_plugin_destroy(plugin); |
222 gaim_plugin_destroy(plugin); |
| 220 |
223 |
| 221 return NULL; |
224 return NULL; |
| 222 } |
225 } |
| 399 |
402 |
| 400 loaded_plugins = g_list_remove(loaded_plugins, plugin); |
403 loaded_plugins = g_list_remove(loaded_plugins, plugin); |
| 401 |
404 |
| 402 g_return_val_if_fail(gaim_plugin_is_loaded(plugin), FALSE); |
405 g_return_val_if_fail(gaim_plugin_is_loaded(plugin), FALSE); |
| 403 |
406 |
| 404 gaim_debug(GAIM_DEBUG_INFO, "plugins", "Unloading plugin %s\n", |
407 gaim_debug_info("plugins", "Unloading plugin %s\n", plugin->info->name); |
| 405 plugin->info->name); |
|
| 406 |
408 |
| 407 /* cancel any pending dialogs the plugin has */ |
409 /* cancel any pending dialogs the plugin has */ |
| 408 gaim_request_close_with_handle(plugin); |
410 gaim_request_close_with_handle(plugin); |
| 409 gaim_notify_close_with_handle(plugin); |
411 gaim_notify_close_with_handle(plugin); |
| 410 |
412 |
| 785 |
786 |
| 786 /************************************************************************** |
787 /************************************************************************** |
| 787 * Plugins subsystem |
788 * Plugins subsystem |
| 788 **************************************************************************/ |
789 **************************************************************************/ |
| 789 void |
790 void |
| 790 gaim_plugins_set_search_paths(size_t count, char **paths) |
791 gaim_plugins_add_search_path(const char *path) |
| 791 { |
792 { |
| 792 size_t s; |
793 g_return_if_fail(path != NULL); |
| 793 |
794 |
| 794 g_return_if_fail(count > 0); |
795 if (g_list_find_custom(search_paths, path, (GCompareFunc)strcmp)) |
| 795 g_return_if_fail(paths != NULL); |
796 return; |
| 796 |
797 |
| 797 if (search_paths != NULL) { |
798 search_paths = g_list_append(search_paths, strdup(path)); |
| 798 for (s = 0; s < search_path_count; s++) |
|
| 799 g_free(search_paths[s]); |
|
| 800 |
|
| 801 g_free(search_paths); |
|
| 802 } |
|
| 803 |
|
| 804 search_paths = g_new0(char *, count); |
|
| 805 |
|
| 806 for (s = 0; s < count; s++) { |
|
| 807 if (paths[s] == NULL) |
|
| 808 search_paths[s] = NULL; |
|
| 809 else |
|
| 810 search_paths[s] = g_strdup(paths[s]); |
|
| 811 } |
|
| 812 |
|
| 813 search_path_count = count; |
|
| 814 } |
799 } |
| 815 |
800 |
| 816 void |
801 void |
| 817 gaim_plugins_unload_all(void) |
802 gaim_plugins_unload_all(void) |
| 818 { |
803 { |
| 881 #ifdef GAIM_PLUGINS |
867 #ifdef GAIM_PLUGINS |
| 882 GDir *dir; |
868 GDir *dir; |
| 883 const gchar *file; |
869 const gchar *file; |
| 884 gchar *path; |
870 gchar *path; |
| 885 GaimPlugin *plugin; |
871 GaimPlugin *plugin; |
| 886 size_t i; |
872 GList *cur; |
| |
873 const char *search_path; |
| 887 |
874 |
| 888 void *handle; |
875 void *handle; |
| 889 |
876 |
| 890 if (!g_module_supported()) |
877 if (!g_module_supported()) |
| 891 return; |
878 return; |
| 892 |
879 |
| 893 handle = gaim_plugins_get_handle(); |
880 handle = gaim_plugins_get_handle(); |
| 894 |
881 |
| |
882 /* TODO: These signals need to be registered in an init function */ |
| 895 gaim_debug_info("plugins", "registering plugin-load signal\n"); |
883 gaim_debug_info("plugins", "registering plugin-load signal\n"); |
| 896 gaim_signal_register(handle, "plugin-load", gaim_marshal_VOID__POINTER, NULL, |
884 gaim_signal_register(handle, "plugin-load", gaim_marshal_VOID__POINTER, NULL, |
| 897 1, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_PLUGIN)); |
885 1, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_PLUGIN)); |
| 898 |
886 |
| 899 gaim_debug_info("plugins", "registering plugin-unload signal\n"); |
887 gaim_debug_info("plugins", "registering plugin-unload signal\n"); |
| 900 gaim_signal_register(handle, "plugin-unload", gaim_marshal_VOID__POINTER, NULL, |
888 gaim_signal_register(handle, "plugin-unload", gaim_marshal_VOID__POINTER, NULL, |
| 901 1, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_PLUGIN)); |
889 1, gaim_value_new(GAIM_TYPE_SUBTYPE, GAIM_SUBTYPE_PLUGIN)); |
| 902 |
890 |
| 903 |
891 |
| 904 for (i = 0; i < search_path_count; i++) { |
892 /* Probe plugins */ |
| 905 if (search_paths[i] == NULL) |
893 for (cur = search_paths; cur != NULL; cur = cur->next) |
| 906 continue; |
894 { |
| 907 |
895 search_path = cur->data; |
| 908 dir = g_dir_open(search_paths[i], 0, NULL); |
896 |
| 909 |
897 dir = g_dir_open(search_path, 0, NULL); |
| 910 if (dir != NULL) { |
898 |
| 911 while ((file = g_dir_read_name(dir)) != NULL) { |
899 if (dir != NULL) |
| 912 path = g_build_filename(search_paths[i], file, NULL); |
900 { |
| 913 |
901 while ((file = g_dir_read_name(dir)) != NULL) |
| 914 if (ext == NULL || is_so_file(file, ext)) |
902 { |
| |
903 path = g_build_filename(search_path, file, NULL); |
| |
904 |
| |
905 if (ext == NULL || has_file_extension(file, ext)) |
| 915 plugin = gaim_plugin_probe(path); |
906 plugin = gaim_plugin_probe(path); |
| 916 |
907 |
| 917 g_free(path); |
908 g_free(path); |
| 918 } |
909 } |
| 919 |
910 |
| 920 g_dir_close(dir); |
911 g_dir_close(dir); |
| 921 } |
912 } |
| 922 } |
913 } |
| 923 |
914 |
| 924 /* See if we have any plugins waiting to load. */ |
915 /* See if we have any plugins waiting to load */ |
| 925 while (load_queue != NULL) |
916 while (load_queue != NULL) |
| 926 { |
917 { |
| 927 plugin = (GaimPlugin *)load_queue->data; |
918 plugin = (GaimPlugin *)load_queue->data; |
| 928 |
919 |
| 929 load_queue = g_list_remove(load_queue, plugin); |
920 load_queue = g_list_remove(load_queue, plugin); |
| 931 if (plugin == NULL || plugin->info == NULL) |
922 if (plugin == NULL || plugin->info == NULL) |
| 932 continue; |
923 continue; |
| 933 |
924 |
| 934 if (plugin->info->type == GAIM_PLUGIN_LOADER) |
925 if (plugin->info->type == GAIM_PLUGIN_LOADER) |
| 935 { |
926 { |
| 936 GList *exts; |
|
| 937 |
|
| 938 /* We'll just load this right now. */ |
927 /* We'll just load this right now. */ |
| 939 if (!gaim_plugin_load(plugin)) |
928 if (!gaim_plugin_load(plugin)) |
| 940 { |
929 { |
| 941 gaim_plugin_destroy(plugin); |
930 gaim_plugin_destroy(plugin); |
| 942 |
931 |
| 943 continue; |
932 continue; |
| 944 } |
933 } |
| 945 |
934 |
| 946 plugin_loaders = g_list_append(plugin_loaders, plugin); |
935 plugin_loaders = g_list_append(plugin_loaders, plugin); |
| 947 |
936 |
| 948 for (exts = GAIM_PLUGIN_LOADER_INFO(plugin)->exts; |
937 for (cur = GAIM_PLUGIN_LOADER_INFO(plugin)->exts; |
| 949 exts != NULL; |
938 cur != NULL; |
| 950 exts = exts->next) |
939 cur = cur->next) |
| 951 { |
940 { |
| 952 gaim_plugins_probe(exts->data); |
941 gaim_plugins_probe(cur->data); |
| 953 } |
942 } |
| 954 } |
943 } |
| 955 else if (plugin->info->type == GAIM_PLUGIN_PROTOCOL) |
944 else if (plugin->info->type == GAIM_PLUGIN_PROTOCOL) |
| 956 { |
945 { |
| 957 /* We'll just load this right now. */ |
946 /* We'll just load this right now. */ |
| 973 protocol_plugins = g_list_insert_sorted(protocol_plugins, plugin, |
962 protocol_plugins = g_list_insert_sorted(protocol_plugins, plugin, |
| 974 (GCompareFunc)compare_prpl); |
963 (GCompareFunc)compare_prpl); |
| 975 } |
964 } |
| 976 } |
965 } |
| 977 |
966 |
| 978 if (load_queue != NULL) |
|
| 979 { |
|
| 980 g_list_free(load_queue); |
|
| 981 load_queue = NULL; |
|
| 982 } |
|
| 983 |
|
| 984 if (probe_cb != NULL) |
967 if (probe_cb != NULL) |
| 985 probe_cb(probe_cb_data); |
968 probe_cb(probe_cb_data); |
| 986 |
969 |
| 987 #endif /* GAIM_PLUGINS */ |
970 #endif /* GAIM_PLUGINS */ |
| 988 } |
971 } |
| 990 gboolean |
973 gboolean |
| 991 gaim_plugin_register(GaimPlugin *plugin) |
974 gaim_plugin_register(GaimPlugin *plugin) |
| 992 { |
975 { |
| 993 g_return_val_if_fail(plugin != NULL, FALSE); |
976 g_return_val_if_fail(plugin != NULL, FALSE); |
| 994 |
977 |
| |
978 /* If this plugin has been registered already then exit */ |
| 995 if (g_list_find(plugins, plugin)) |
979 if (g_list_find(plugins, plugin)) |
| 996 return TRUE; |
980 return TRUE; |
| 997 |
981 |
| |
982 /* Ensure the plugin has the requisite information */ |
| 998 if (plugin->info->type == GAIM_PLUGIN_LOADER) |
983 if (plugin->info->type == GAIM_PLUGIN_LOADER) |
| 999 { |
984 { |
| 1000 GaimPluginLoaderInfo *loader_info; |
985 GaimPluginLoaderInfo *loader_info; |
| 1001 |
986 |
| 1002 loader_info = GAIM_PLUGIN_LOADER_INFO(plugin); |
987 loader_info = GAIM_PLUGIN_LOADER_INFO(plugin); |
| 1003 |
988 |
| 1004 if (loader_info == NULL) |
989 if (loader_info == NULL) |
| 1005 { |
990 { |
| 1006 gaim_debug(GAIM_DEBUG_ERROR, "plugins", "%s is unloadable\n", |
991 gaim_debug_error("plugins", "%s is unloadable\n", |
| 1007 plugin->path); |
992 plugin->path); |
| 1008 return FALSE; |
993 return FALSE; |
| 1009 } |
994 } |
| 1010 |
|
| 1011 load_queue = g_list_append(load_queue, plugin); |
|
| 1012 } |
995 } |
| 1013 else if (plugin->info->type == GAIM_PLUGIN_PROTOCOL) |
996 else if (plugin->info->type == GAIM_PLUGIN_PROTOCOL) |
| 1014 { |
997 { |
| 1015 GaimPluginProtocolInfo *prpl_info; |
998 GaimPluginProtocolInfo *prpl_info; |
| 1016 |
999 |
| 1017 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin); |
1000 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin); |
| 1018 |
1001 |
| 1019 if (prpl_info == NULL) |
1002 if (prpl_info == NULL) |
| 1020 { |
1003 { |
| 1021 gaim_debug(GAIM_DEBUG_ERROR, "plugins", "%s is unloadable\n", |
1004 gaim_debug_error("plugins", "%s is unloadable\n", |
| 1022 plugin->path); |
1005 plugin->path); |
| 1023 return FALSE; |
1006 return FALSE; |
| 1024 } |
1007 } |
| 1025 |
1008 } |
| 1026 load_queue = g_list_append(load_queue, plugin); |
1009 |
| 1027 } |
1010 /* This plugin should be probed and maybe loaded--add it to the queue */ |
| |
1011 load_queue = g_list_append(load_queue, plugin); |
| 1028 |
1012 |
| 1029 plugins = g_list_append(plugins, plugin); |
1013 plugins = g_list_append(plugins, plugin); |
| 1030 |
1014 |
| 1031 return TRUE; |
1015 return TRUE; |
| 1032 } |
1016 } |