Mercurial > pidgin
comparison src/module.c @ 3551:cd938f18f3f8
[gaim-migrate @ 3626]
In the interest of continued progress, I pulled what's usable out of my
development tree and am committing it.
Here, we have gotten rid of the plugins dialog and perl menu under Tools and
put them both in preferences. Perl scripts now work like plugins--you have
to load them explicitly (it will probe $prefix/lib/gaim and $HOME/.gaim for
them) and you can unload them (although right now, this is entirely unreliable)
Oh, and I broke all your perl scripts. Sorry about that. Don't try fixing
them yet, though--I'm gonna make unloading single scripts more reliable
tommorow.
I should also finish Phase Two tommorow as well.
committer: Tailor Script <tailor@pidgin.im>
| author | Sean Egan <seanegan@gmail.com> |
|---|---|
| date | Thu, 26 Sep 2002 07:37:52 +0000 |
| parents | 6b0cb60162f4 |
| children | e120097bbd72 |
comparison
equal
deleted
inserted
replaced
| 3550:e9b2003ee562 | 3551:cd938f18f3f8 |
|---|---|
| 34 #include <config.h> | 34 #include <config.h> |
| 35 #endif | 35 #endif |
| 36 | 36 |
| 37 #include "gaim.h" | 37 #include "gaim.h" |
| 38 | 38 |
| 39 #ifdef GAIM_PLUGINS | |
| 40 | |
| 41 #include <string.h> | 39 #include <string.h> |
| 42 #include <sys/time.h> | 40 #include <sys/time.h> |
| 43 | 41 |
| 44 #include <sys/types.h> | 42 #include <sys/types.h> |
| 45 #include <sys/stat.h> | 43 #include <sys/stat.h> |
| 49 #include <stdlib.h> | 47 #include <stdlib.h> |
| 50 | 48 |
| 51 /* ------------------ Global Variables ----------------------- */ | 49 /* ------------------ Global Variables ----------------------- */ |
| 52 | 50 |
| 53 GList *plugins = NULL; | 51 GList *plugins = NULL; |
| 52 GList *probed_plugins = NULL; | |
| 54 GList *callbacks = NULL; | 53 GList *callbacks = NULL; |
| 55 | 54 |
| 56 char *last_dir = NULL; | 55 char *last_dir = NULL; |
| 57 | 56 |
| 58 /* --------------- Function Declarations --------------------- */ | 57 /* --------------- Function Declarations --------------------- */ |
| 59 | 58 |
| 60 struct gaim_plugin * load_plugin(const char *); | 59 struct gaim_plugin * load_plugin(const char *); |
| 60 #ifdef GAIM_PLUGINS | |
| 61 void unload_plugin(struct gaim_plugin *p); | 61 void unload_plugin(struct gaim_plugin *p); |
| 62 struct gaim_plugin *reload_plugin(struct gaim_plugin *p); | 62 struct gaim_plugin *reload_plugin(struct gaim_plugin *p); |
| 63 | |
| 64 void gaim_signal_connect(GModule *, enum gaim_event, void *, void *); | 63 void gaim_signal_connect(GModule *, enum gaim_event, void *, void *); |
| 65 void gaim_signal_disconnect(GModule *, enum gaim_event, void *); | 64 void gaim_signal_disconnect(GModule *, enum gaim_event, void *); |
| 66 void gaim_plugin_unload(GModule *); | 65 void gaim_plugin_unload(GModule *); |
| 67 | 66 |
| 68 /* --------------- Static Function Declarations ------------- */ | 67 /* --------------- Static Function Declarations ------------- */ |
| 69 | 68 |
| 70 static void plugin_remove_callbacks(GModule *); | 69 static void plugin_remove_callbacks(GModule *); |
| 71 | 70 #endif |
| 72 /* ------------------ Code Below ---------------------------- */ | 71 /* ------------------ Code Below ---------------------------- */ |
| 73 | 72 |
| 74 struct gaim_plugin *load_plugin(const char *filename) | 73 static int is_so_file(char *filename, char *ext) |
| 75 { | 74 { |
| 75 int len; | |
| 76 if (!filename) return 0; | |
| 77 if (!filename[0]) return 0; | |
| 78 len = strlen(filename); | |
| 79 len -= strlen(ext); | |
| 80 if (len < 0) return 0; | |
| 81 return (!strncmp(filename + len, ext, strlen(ext))); | |
| 82 } | |
| 83 | |
| 84 void gaim_probe_plugins() { | |
| 85 GDir *dir; | |
| 86 const gchar *file; | |
| 87 gchar *path; | |
| 88 struct gaim_plugin_description *plugdes; | |
| 76 struct gaim_plugin *plug; | 89 struct gaim_plugin *plug; |
| 77 GList *c = plugins; | 90 char userspace[128]; |
| 91 char *probedirs[] = {LIBDIR, &userspace, 0}; | |
| 92 #if GAIM_PLUGINS | |
| 78 char *(*gaim_plugin_init)(GModule *); | 93 char *(*gaim_plugin_init)(GModule *); |
| 79 char *(*cfunc)(); | 94 char *(*cfunc)(); |
| 80 char *error; | 95 int l; |
| 81 char *retval; | 96 struct gaim_plugin_description *(*desc)(); |
| 97 GModule *handle; | |
| 98 #endif | |
| 99 | |
| 100 g_snprintf(userspace, sizeof(userspace), "%s" G_DIR_SEPARATOR_S ".gaim", g_get_home_dir()); | |
| 101 | |
| 102 for (l=0; probedirs[l]; l++) { | |
| 103 dir = g_dir_open(probedirs[l], 0, NULL); | |
| 104 if (dir) { | |
| 105 while ((file = g_dir_read_name(dir))) { | |
| 106 #ifdef GAIM_PLUGINS | |
| 107 if (is_so_file(file, ".so") && g_module_supported()) { | |
| 108 path = g_build_filename(probedirs[l], file, NULL); | |
| 109 handle = g_module_open(path, 0); | |
| 110 if (!handle) { | |
| 111 debug_printf("%s is unloadable: %s\n", file, g_module_error()); | |
| 112 continue; | |
| 113 } | |
| 114 if (!g_module_symbol(handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) { | |
| 115 debug_printf("%s is unloadable %s\n", file, g_module_error()); | |
| 116 g_module_close(handle); | |
| 117 continue; | |
| 118 } | |
| 119 plug = g_new0(struct gaim_plugin, 1); | |
| 120 g_snprintf(plug->path, sizeof(plug->path), path); | |
| 121 plug->type = plugin; | |
| 122 g_free(path); | |
| 123 if (g_module_symbol(handle, "gaim_plugin_desc", (gpointer *)&desc)) { | |
| 124 memcpy(&(plug->desc), desc(), sizeof(plug->desc)); | |
| 125 } else { | |
| 126 if (g_module_symbol(handle, "name", (gpointer *)&cfunc)) { | |
| 127 plug->desc.name = g_strdup(cfunc()); | |
| 128 } | |
| 129 if (g_module_symbol(handle, "description", (gpointer *)&cfunc)) { | |
| 130 plug->desc.description = g_strdup(cfunc()); | |
| 131 } | |
| 132 } | |
| 133 probed_plugins = g_list_append(probed_plugins, plug); | |
| 134 g_module_close(handle); | |
| 135 } | |
| 136 #endif | |
| 137 #ifdef USE_PERL | |
| 138 if (is_so_file(file, ".pl")) { | |
| 139 path = g_build_filename(LIBDIR, file, NULL); | |
| 140 plug = probe_perl(path); | |
| 141 if (plug) | |
| 142 probed_plugins = g_list_append(probed_plugins, plug); | |
| 143 g_free(path); | |
| 144 } | |
| 145 #endif | |
| 146 } | |
| 147 g_dir_close(dir); | |
| 148 } | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 #ifdef GAIM_PLUGINS | |
| 153 struct gaim_plugin *load_plugin(const char *filename) | |
| 154 { | |
| 155 struct gaim_plugin *plug; | |
| 156 struct gaim_plugin_description *desc; | |
| 157 struct gaim_plugin_description *(*gaim_plugin_desc)(); | |
| 158 char *(*cfunc)(); | |
| 159 GList *c = plugins; | |
| 160 GList *p = probed_plugins; | |
| 161 char *(*gaim_plugin_init)(GModule *); | |
| 162 char *error, *retval, *tmp; | |
| 163 gboolean newplug = FALSE; | |
| 82 | 164 |
| 83 if (!g_module_supported()) | 165 if (!g_module_supported()) |
| 84 return NULL; | 166 return NULL; |
| 85 if (filename && !strlen(filename)) | 167 if (!filename || !strlen(filename)) |
| 86 return NULL; | 168 return NULL; |
| 87 | 169 |
| 88 while (filename && c) { | 170 while (filename && p) { |
| 89 plug = (struct gaim_plugin *)c->data; | 171 plug = (struct gaim_plugin *)p->data; |
| 90 if (!strcmp(filename, g_module_name(plug->handle))) { | 172 if (!strcmp(filename, plug->path)) |
| 91 /* just need to reload plugin */ | 173 break; |
| 92 return reload_plugin(plug); | 174 p = p->next; |
| 93 } else | 175 } |
| 94 c = g_list_next(c); | 176 |
| 95 } | 177 if (plug && plug->handle) { |
| 96 plug = g_malloc(sizeof *plug); | 178 reload_plugin(plug); |
| 97 | 179 return NULL; |
| 98 if (last_dir) | 180 } |
| 99 g_free(last_dir); | 181 |
| 100 last_dir = g_dirname(filename); | 182 if (!plug) { |
| 101 | 183 plug = g_new0(struct gaim_plugin, 1); |
| 184 g_snprintf(plug->path, sizeof(plug->path), filename); | |
| 185 newplug = TRUE; | |
| 186 } | |
| 187 | |
| 102 debug_printf("Loading %s\n", filename); | 188 debug_printf("Loading %s\n", filename); |
| 103 plug->handle = g_module_open(filename, 0); | 189 plug->handle = g_module_open(filename, 0); |
| 104 if (!plug->handle) { | 190 if (!plug->handle) { |
| 105 error = (char *)g_module_error(); | 191 error = (char *)g_module_error(); |
| 106 do_error_dialog(_("Gaim was unable to load your plugin."), error, GAIM_ERROR); | 192 plug->handle = NULL; |
| 107 g_free(plug); | 193 tmp = plug->desc.description; |
| 194 plug->desc.description = g_strdup_printf("<span weight=\"bold\" foreground=\"red\">%s</span>\n\n%s", error, tmp); | |
| 195 g_free(tmp); | |
| 108 return NULL; | 196 return NULL; |
| 109 } | 197 } |
| 110 | 198 |
| 111 if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) { | 199 if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) { |
| 112 do_error_dialog(_("Gaim was unable to load your plugin."), g_module_error(), GAIM_ERROR); | |
| 113 g_module_close(plug->handle); | 200 g_module_close(plug->handle); |
| 114 g_free(plug); | 201 plug->handle = NULL; |
| 202 tmp = plug->desc.description; | |
| 203 plug->desc.description = g_strdup_printf("<span foreground=\"red\">%s</span>\n\n%s", g_module_error(), tmp); | |
| 204 g_free(tmp); | |
| 115 return NULL; | 205 return NULL; |
| 116 } | 206 } |
| 117 | 207 |
| 118 retval = gaim_plugin_init(plug->handle); | 208 retval = gaim_plugin_init(plug->handle); |
| 119 debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL"); | 209 debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL"); |
| 120 if (retval) { | 210 if (retval) { |
| 121 plugin_remove_callbacks(plug->handle); | 211 plugin_remove_callbacks(plug->handle); |
| 122 do_error_dialog("Gaim was unable to load your plugin.", retval, GAIM_ERROR); | 212 do_error_dialog("Gaim was unable to load your plugin.", retval, GAIM_ERROR); |
| 123 g_module_close(plug->handle); | 213 g_module_close(plug->handle); |
| 124 g_free(plug); | 214 plug->handle = NULL; |
| 125 return NULL; | 215 return NULL; |
| 126 } | 216 } |
| 127 | 217 |
| 128 plugins = g_list_append(plugins, plug); | 218 plugins = g_list_append(plugins, plug); |
| 129 | 219 |
| 130 if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) { | 220 if (newplug) { |
| 131 plug->name = cfunc(); | 221 g_snprintf(plug->path, sizeof(plug->path), filename); |
| 132 } else { | 222 if (g_module_symbol(plug->handle, "gaim_plugin_desc", (gpointer *)&gaim_plugin_desc)) { |
| 133 plug->name = NULL; | 223 desc = gaim_plugin_desc(); |
| 134 } | 224 plug->desc.name = desc->name; |
| 135 | 225 } else { |
| 136 if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc)) | 226 if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) { |
| 137 plug->description = cfunc(); | 227 plug->desc.name = g_strdup(cfunc()); |
| 138 else | 228 } |
| 139 plug->description = NULL; | 229 if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc)) { |
| 140 | 230 plug->desc.description = g_strdup(cfunc()); |
| 231 } | |
| 232 } | |
| 233 probed_plugins = g_list_append(probed_plugins, plug); | |
| 234 } | |
| 235 | |
| 141 save_prefs(); | 236 save_prefs(); |
| 142 return plug; | 237 return plug; |
| 238 | |
| 143 } | 239 } |
| 144 | 240 |
| 145 static void unload_gaim_plugin(struct gaim_plugin *p) | 241 static void unload_gaim_plugin(struct gaim_plugin *p) |
| 146 { | 242 { |
| 147 void (*gaim_plugin_remove)(); | 243 void (*gaim_plugin_remove)(); |
| 153 gaim_plugin_remove(); | 249 gaim_plugin_remove(); |
| 154 | 250 |
| 155 plugin_remove_callbacks(p->handle); | 251 plugin_remove_callbacks(p->handle); |
| 156 | 252 |
| 157 plugins = g_list_remove(plugins, p); | 253 plugins = g_list_remove(plugins, p); |
| 158 g_free(p); | 254 p->handle = NULL; |
| 159 save_prefs(); | 255 save_prefs(); |
| 160 } | 256 } |
| 161 | 257 |
| 162 void unload_plugin(struct gaim_plugin *p) | 258 void unload_plugin(struct gaim_plugin *p) |
| 163 { | 259 { |
| 192 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) | 288 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) |
| 193 gaim_plugin_remove(); | 289 gaim_plugin_remove(); |
| 194 plugin_remove_callbacks(p->handle); | 290 plugin_remove_callbacks(p->handle); |
| 195 plugins = g_list_remove(plugins, p); | 291 plugins = g_list_remove(plugins, p); |
| 196 g_free(p); | 292 g_free(p); |
| 197 /* XXX CUI need to tell UI what happened, but not like this */ | 293 /* XXX CUI need to tell UI what happened, but not like this |
| 198 update_show_plugins(); | 294 update_show_plugins(); */ |
| 199 | 295 |
| 200 g_timeout_add(5000, unload_timeout, handle); | 296 g_timeout_add(5000, unload_timeout, handle); |
| 201 } | 297 } |
| 202 | 298 |
| 203 /* Do unload/load cycle of plugin. */ | 299 /* Do unload/load cycle of plugin. */ |
| 379 int plugin_event(enum gaim_event event, ...) | 475 int plugin_event(enum gaim_event event, ...) |
| 380 { | 476 { |
| 381 #ifdef GAIM_PLUGINS | 477 #ifdef GAIM_PLUGINS |
| 382 GList *c = callbacks; | 478 GList *c = callbacks; |
| 383 struct gaim_callback *g; | 479 struct gaim_callback *g; |
| 480 #endif | |
| 384 va_list arrg; | 481 va_list arrg; |
| 385 void *arg1 = NULL, | 482 void *arg1 = NULL, |
| 386 *arg2 = NULL, | 483 *arg2 = NULL, |
| 387 *arg3 = NULL, | 484 *arg3 = NULL, |
| 388 *arg4 = NULL, | 485 *arg4 = NULL, |
| 389 *arg5 = NULL; | 486 *arg5 = NULL; |
| 390 #endif | 487 |
| 391 | 488 |
| 392 debug_printf("%s\n", event_name(event)); | 489 debug_printf("%s\n", event_name(event)); |
| 393 | 490 |
| 394 #ifdef GAIM_PLUGINS | 491 #ifdef GAIM_PLUGINS |
| 395 while (c) { | 492 while (c) { |
