Mercurial > pidgin.yaz
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 |