comparison src/plugin.c @ 10447:6feef0a9098a

[gaim-migrate @ 11712] A few minor improvements and some documentation updates. Conscious evolution in the back of your mind... committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Wed, 29 Dec 2004 21:53:59 +0000
parents f9ff0882e247
children 577fdf4110fc
comparison
equal deleted inserted replaced
10446:904d03bfccce 10447:6feef0a9098a
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;
77 75
78 void * 76 void *
79 gaim_plugins_get_handle(void) 77 gaim_plugins_get_handle(void)
80 { 78 {
81 static int handle; 79 static int handle;
80
82 return &handle; 81 return &handle;
83 } 82 }
84 83
85 84
86 #ifdef GAIM_PLUGINS 85 #ifdef GAIM_PLUGINS
87 static int 86 static gboolean
88 is_so_file(const char *filename, const char *ext) 87 has_file_extension(const char *filename, const char *ext)
89 { 88 {
90 int len, extlen; 89 int len, extlen;
91 90
92 if (filename == NULL || *filename == '\0' || ext == NULL) 91 if (filename == NULL || *filename == '\0' || ext == NULL)
93 return 0; 92 return 0;
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
453 455
454 /* TODO */ 456 /* TODO */
455 if (unload_cb != NULL) 457 if (unload_cb != NULL)
456 unload_cb(plugin, unload_cb_data); 458 unload_cb(plugin, unload_cb_data);
457 459
458 /* I suppose this is the right place to call this... */
459 gaim_signal_emit(gaim_plugins_get_handle(), "plugin-unload", plugin); 460 gaim_signal_emit(gaim_plugins_get_handle(), "plugin-unload", plugin);
460 461
461 gaim_prefs_disconnect_by_handle(plugin); 462 gaim_prefs_disconnect_by_handle(plugin);
462 463
463 return TRUE; 464 return TRUE;
534 next_l = l->next; 535 next_l = l->next;
535 536
536 p2 = l->data; 537 p2 = l->data;
537 538
538 if (p2->path != NULL && 539 if (p2->path != NULL &&
539 is_so_file(p2->path, exts->data)) 540 has_file_extension(p2->path, exts->data))
540 { 541 {
541 gaim_plugin_destroy(p2); 542 gaim_plugin_destroy(p2);
542 } 543 }
543 } 544 }
544 } 545 }
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 {
833 gaim_plugin_destroy(plugins->data); 818 gaim_plugin_destroy(plugins->data);
834 819
835 #endif /* GAIM_PLUGINS */ 820 #endif /* GAIM_PLUGINS */
836 } 821 }
837 822
823 /* TODO: Change this to accept a GList* */
838 void 824 void
839 gaim_plugins_load_saved(const char *key) 825 gaim_plugins_load_saved(const char *key)
840 { 826 {
841 #ifdef GAIM_PLUGINS 827 #ifdef GAIM_PLUGINS
842 GList *f, *files; 828 GList *f, *files;
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 }
1196 act->label = label; 1180 act->label = label;
1197 act->callback = callback; 1181 act->callback = callback;
1198 1182
1199 return act; 1183 return act;
1200 } 1184 }
1201