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