comparison src/plugins.c @ 1047:ece2d1543b20

[gaim-migrate @ 1057] Plugins now use GModule. Protocol plugins can be dynamically updated. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Wed, 01 Nov 2000 22:30:36 +0000
parents 67ed2ee5be9f
children d50d3abb9eb7
comparison
equal deleted inserted replaced
1046:4593605da0e2 1047:ece2d1543b20
68 /* --------------- Function Declarations --------------------- */ 68 /* --------------- Function Declarations --------------------- */
69 69
70 void show_plugins (GtkWidget *, gpointer); 70 void show_plugins (GtkWidget *, gpointer);
71 void load_plugin (char *); 71 void load_plugin (char *);
72 72
73 void gaim_signal_connect (void *, enum gaim_event, void *, void *); 73 void gaim_signal_connect (GModule *, enum gaim_event, void *, void *);
74 void gaim_signal_disconnect(void *, enum gaim_event, void *); 74 void gaim_signal_disconnect(GModule *, enum gaim_event, void *);
75 void gaim_plugin_unload (void *); 75 void gaim_plugin_unload (GModule *);
76 76
77 static void destroy_plugins (GtkWidget *, gpointer); 77 static void destroy_plugins (GtkWidget *, gpointer);
78 static void load_file (GtkWidget *, gpointer); 78 static void load_file (GtkWidget *, gpointer);
79 static void load_which_plugin(GtkWidget *, gpointer); 79 static void load_which_plugin(GtkWidget *, gpointer);
80 static void unload (GtkWidget *, gpointer); 80 static void unload (GtkWidget *, gpointer);
81 static void unload_immediate (GModule *);
81 static void list_clicked (GtkWidget *, struct gaim_plugin *); 82 static void list_clicked (GtkWidget *, struct gaim_plugin *);
82 static void update_show_plugins(); 83 static void update_show_plugins();
83 static void hide_plugins (GtkWidget *, gpointer); 84 static void hide_plugins (GtkWidget *, gpointer);
84 85
85 /* ------------------ Code Below ---------------------------- */ 86 /* ------------------ Code Below ---------------------------- */
144 } 145 }
145 146
146 void load_plugin(char *filename) { 147 void load_plugin(char *filename) {
147 struct gaim_plugin *plug; 148 struct gaim_plugin *plug;
148 GList *c = plugins; 149 GList *c = plugins;
149 int (*gaim_plugin_init)(); 150 char *(*gaim_plugin_init)(GModule *);
150 char *(*gaim_plugin_error)(int);
151 char *(*cfunc)(); 151 char *(*cfunc)();
152 char *error; 152 char *error;
153 int retval; 153 char *retval;
154 char *plugin_error; 154 char *tmp_filename;
155 155
156 if (!g_module_supported()) return;
156 if (filename == NULL) return; 157 if (filename == NULL) return;
157 /* i shouldn't be checking based solely on path, but i'm lazy */ 158
158 while (c) { 159 while (c) {
159 plug = (struct gaim_plugin *)c->data; 160 plug = (struct gaim_plugin *)c->data;
160 if (!strcmp(filename, plug->filename)) { 161 if (!strcmp(filename, g_module_name(plug->handle))) {
161 debug_printf( _("Already loaded %s, not reloading.\n"), filename); 162 void (*gaim_plugin_remove)();
162 return; 163 if (g_module_symbol(plug->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
163 } 164 (*gaim_plugin_remove)();
164 c = g_list_next(c); 165
166 unload_immediate(plug->handle);
167 c = plugins;
168 } else
169 c = g_list_next(c);
165 } 170 }
166 plug = g_malloc(sizeof *plug); 171 plug = g_malloc(sizeof *plug);
167 if (!g_path_is_absolute(filename)) 172 if (!g_path_is_absolute(filename))
168 plug->filename = g_strconcat(g_get_home_dir(), G_DIR_SEPARATOR_S, 173 tmp_filename = g_strconcat(g_get_home_dir(), G_DIR_SEPARATOR_S,
169 PLUGIN_DIR, filename, NULL); 174 PLUGIN_DIR, filename, NULL);
170 else 175 else
171 plug->filename = g_strdup(filename); 176 tmp_filename = g_strdup(filename);
172 177
173 if (last_dir) 178 if (last_dir)
174 g_free(last_dir); 179 g_free(last_dir);
175 last_dir = g_dirname(plug->filename); 180 last_dir = g_dirname(tmp_filename);
176 181
177 debug_printf("Loading %s\n", filename); 182 debug_printf("Loading %s\n", tmp_filename);
178 /* do NOT `OR' with RTLD_GLOBAL, otherwise plugins may conflict 183 plug->handle = g_module_open(tmp_filename, 0);
179 * (it's really just a way to work around other people's bad 184 g_free(tmp_filename);
180 * programming, by not using RTLD_GLOBAL :P ) */
181 plug->handle = dlopen(plug->filename, RTLD_LAZY);
182 if (!plug->handle) { 185 if (!plug->handle) {
183 error = (char *)dlerror(); 186 error = (char *)g_module_error();
184 do_error_dialog(error, _("Plugin Error")); 187 do_error_dialog(error, _("Plugin Error"));
185 g_free(plug->filename);
186 g_free(plug); 188 g_free(plug);
187 return; 189 return;
188 } 190 }
189 191
190 gaim_plugin_init = dlsym(plug->handle, "gaim_plugin_init"); 192 if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) {
191 if ((error = (char *)dlerror()) != NULL) { 193 do_error_dialog(g_module_error(), _("Plugin Error"));
192 do_error_dialog(error, _("Plugin Error")); 194 g_module_close(plug->handle);
193 dlclose(plug->handle);
194 g_free(plug->filename);
195 g_free(plug); 195 g_free(plug);
196 return; 196 return;
197 } 197 }
198 198
199 retval = (*gaim_plugin_init)(plug->handle); 199 retval = (*gaim_plugin_init)(plug->handle);
200 debug_printf("loaded plugin returned %d\n", retval); 200 debug_printf("loaded plugin returned %d\n", retval);
201 if (retval < 0) { 201 if (retval) {
202 GList *c = callbacks; 202 GList *c = callbacks;
203 struct gaim_callback *g; 203 struct gaim_callback *g;
204 while (c) { 204 while (c) {
205 g = (struct gaim_callback *)c->data; 205 g = (struct gaim_callback *)c->data;
206 if (g->handle == plug->handle) { 206 if (g->handle == plug->handle) {
214 } 214 }
215 } else { 215 } else {
216 c = g_list_next(c); 216 c = g_list_next(c);
217 } 217 }
218 } 218 }
219 gaim_plugin_error = dlsym(plug->handle, "gaim_plugin_error"); 219 do_error_dialog(retval, _("Plugin Error"));
220 if ((error = (char *)dlerror()) == NULL) { 220 g_module_close(plug->handle);
221 plugin_error = (*gaim_plugin_error)(retval);
222 if (plugin_error)
223 do_error_dialog(plugin_error, _("Plugin Error"));
224 }
225 dlclose(plug->handle);
226 g_free(plug->filename);
227 g_free(plug); 221 g_free(plug);
228 return; 222 return;
229 } 223 }
230 224
231 plugins = g_list_append(plugins, plug); 225 plugins = g_list_append(plugins, plug);
232 226
233 cfunc = dlsym(plug->handle, "name"); 227 if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc))
234 if ((error = (char *)dlerror()) == NULL)
235 plug->name = (*cfunc)(); 228 plug->name = (*cfunc)();
236 else 229 else
237 plug->name = NULL; 230 plug->name = NULL;
238 231
239 cfunc = dlsym(plug->handle, "description"); 232 if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc))
240 if ((error = (char *)dlerror()) == NULL)
241 plug->description = (*cfunc)(); 233 plug->description = (*cfunc)();
242 else 234 else
243 plug->description = NULL; 235 plug->description = NULL;
244 236
245 update_show_plugins(); 237 update_show_plugins();
330 gtk_box_pack_start(GTK_BOX(page), topbox, TRUE, TRUE, 0); 322 gtk_box_pack_start(GTK_BOX(page), topbox, TRUE, TRUE, 0);
331 gtk_box_pack_start(GTK_BOX(page), botbox, FALSE, FALSE, 0); 323 gtk_box_pack_start(GTK_BOX(page), botbox, FALSE, FALSE, 0);
332 324
333 while (plugs) { 325 while (plugs) {
334 p = (struct gaim_plugin *)plugs->data; 326 p = (struct gaim_plugin *)plugs->data;
335 label = gtk_label_new(p->filename); 327 label = gtk_label_new(g_module_name(p->handle));
336 list_item = gtk_list_item_new(); 328 list_item = gtk_list_item_new();
337 gtk_container_add(GTK_CONTAINER(list_item), label); 329 gtk_container_add(GTK_CONTAINER(list_item), label);
338 gtk_signal_connect(GTK_OBJECT(list_item), "select", 330 gtk_signal_connect(GTK_OBJECT(list_item), "select",
339 GTK_SIGNAL_FUNC(list_clicked), p); 331 GTK_SIGNAL_FUNC(list_clicked), p);
340 gtk_object_set_user_data(GTK_OBJECT(list_item), p); 332 gtk_object_set_user_data(GTK_OBJECT(list_item), p);
375 if (plugwindow == NULL) return; 367 if (plugwindow == NULL) return;
376 368
377 gtk_list_clear_items(GTK_LIST(pluglist), 0, -1); 369 gtk_list_clear_items(GTK_LIST(pluglist), 0, -1);
378 while (plugs) { 370 while (plugs) {
379 p = (struct gaim_plugin *)plugs->data; 371 p = (struct gaim_plugin *)plugs->data;
380 label = gtk_label_new(p->filename); 372 label = gtk_label_new(g_module_name(p->handle));
381 list_item = gtk_list_item_new(); 373 list_item = gtk_list_item_new();
382 gtk_container_add(GTK_CONTAINER(list_item), label); 374 gtk_container_add(GTK_CONTAINER(list_item), label);
383 gtk_signal_connect(GTK_OBJECT(list_item), "select", 375 gtk_signal_connect(GTK_OBJECT(list_item), "select",
384 GTK_SIGNAL_FUNC(list_clicked), p); 376 GTK_SIGNAL_FUNC(list_clicked), p);
385 gtk_object_set_user_data(GTK_OBJECT(list_item), p); 377 gtk_object_set_user_data(GTK_OBJECT(list_item), p);
400 392
401 void unload(GtkWidget *w, gpointer data) { 393 void unload(GtkWidget *w, gpointer data) {
402 GList *i; 394 GList *i;
403 struct gaim_plugin *p; 395 struct gaim_plugin *p;
404 void (*gaim_plugin_remove)(); 396 void (*gaim_plugin_remove)();
405 char *error;
406 397
407 i = GTK_LIST(pluglist)->selection; 398 i = GTK_LIST(pluglist)->selection;
408 399
409 if (i == NULL) return; 400 if (i == NULL) return;
410 401
411 p = gtk_object_get_user_data(GTK_OBJECT(i->data)); 402 p = gtk_object_get_user_data(GTK_OBJECT(i->data));
412 403
413 /* Attempt to call the plugin's remove function (if there) */ 404 /* Attempt to call the plugin's remove function (if there) */
414 gaim_plugin_remove = dlsym(p->handle, "gaim_plugin_remove"); 405 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
415 if ((error = (char *)dlerror()) == NULL)
416 (*gaim_plugin_remove)(); 406 (*gaim_plugin_remove)();
417 407
418 gaim_plugin_unload(p->handle); 408 unload_immediate(p->handle);
419 } 409 }
420 410
421 /* gaim_plugin_unload serves 2 purposes: 1. so plugins can unload themselves 411 static void unload_for_real(void *handle) {
422 * 2. to make my life easier */
423 void gaim_plugin_unload(void *handle) {
424 GList *i; 412 GList *i;
425 struct gaim_plugin *p = NULL; 413 struct gaim_plugin *p = NULL;
426 GList *c = callbacks; 414 GList *c = callbacks;
427 struct gaim_callback *g; 415 struct gaim_callback *g;
428 416
436 } 424 }
437 425
438 if (!p) 426 if (!p)
439 return; 427 return;
440 428
441 sprintf(debug_buff, "Unloading %s\n", p->filename); 429 sprintf(debug_buff, "Unloading %s\n", g_module_name(p->handle));
442 debug_print(debug_buff); 430 debug_print(debug_buff);
443 431
444 sprintf(debug_buff, "%d callbacks to search\n", g_list_length(callbacks)); 432 sprintf(debug_buff, "%d callbacks to search\n", g_list_length(callbacks));
445 debug_print(debug_buff); 433 debug_print(debug_buff);
446 434
460 c = g_list_next(c); 448 c = g_list_next(c);
461 } 449 }
462 } 450 }
463 451
464 plugins = g_list_remove(plugins, p); 452 plugins = g_list_remove(plugins, p);
465 g_free(p->filename);
466 /* we don't dlclose(p->handle) in case if we still need code from the plugin later */
467 g_free(p); 453 g_free(p);
468 if (config) gtk_widget_set_sensitive(config, 0); 454 if (config) gtk_widget_set_sensitive(config, 0);
469 update_show_plugins(); 455 update_show_plugins();
470 save_prefs(); 456 save_prefs();
457 }
458
459 void unload_immediate(GModule *handle) {
460 unload_for_real(handle);
461 g_module_close(handle);
462 }
463
464 static gint unload_timeout(GModule *handle) {
465 g_module_close(handle);
466 return FALSE;
467 }
468
469 void gaim_plugin_unload(GModule *handle) {
470 unload_for_real(handle);
471 gtk_timeout_add(5000, (GtkFunction)unload_timeout, handle);
471 } 472 }
472 473
473 void list_clicked(GtkWidget *w, struct gaim_plugin *p) { 474 void list_clicked(GtkWidget *w, struct gaim_plugin *p) {
474 gchar *temp; 475 gchar *temp;
475 guint text_len; 476 guint text_len;
485 temp = g_strdup_printf("%s\n%s", p->name, p->description); 486 temp = g_strdup_printf("%s\n%s", p->name, p->description);
486 gtk_text_insert(GTK_TEXT(plugtext), NULL, NULL, NULL, temp, -1); 487 gtk_text_insert(GTK_TEXT(plugtext), NULL, NULL, NULL, temp, -1);
487 g_free(temp); 488 g_free(temp);
488 489
489 /* Find out if this plug-in has a configuration function */ 490 /* Find out if this plug-in has a configuration function */
490 gaim_plugin_config = dlsym(p->handle, "gaim_plugin_config"); 491 if (g_module_symbol(p->handle, "gaim_plugin_config", (gpointer *)&gaim_plugin_config)) {
491 if ((error = (char *)dlerror()) == NULL) {
492 confighandle = gtk_signal_connect(GTK_OBJECT(config), "clicked", 492 confighandle = gtk_signal_connect(GTK_OBJECT(config), "clicked",
493 GTK_SIGNAL_FUNC(gaim_plugin_config), NULL); 493 GTK_SIGNAL_FUNC(gaim_plugin_config), NULL);
494 gtk_widget_set_sensitive(config, 1); 494 gtk_widget_set_sensitive(config, 1);
495 } else { 495 } else {
496 confighandle = 0; 496 confighandle = 0;
504 plugwindow = NULL; 504 plugwindow = NULL;
505 config = NULL; 505 config = NULL;
506 confighandle = 0; 506 confighandle = 0;
507 } 507 }
508 508
509 void gaim_signal_connect(void *handle, enum gaim_event which, 509 void gaim_signal_connect(GModule *handle, enum gaim_event which,
510 void *func, void *data) { 510 void *func, void *data) {
511 struct gaim_callback *call = g_new0(struct gaim_callback, 1); 511 struct gaim_callback *call = g_new0(struct gaim_callback, 1);
512 call->handle = handle; 512 call->handle = handle;
513 call->event = which; 513 call->event = which;
514 call->function = func; 514 call->function = func;
517 callbacks = g_list_append(callbacks, call); 517 callbacks = g_list_append(callbacks, call);
518 sprintf(debug_buff, "Adding callback %d\n", g_list_length(callbacks)); 518 sprintf(debug_buff, "Adding callback %d\n", g_list_length(callbacks));
519 debug_print(debug_buff); 519 debug_print(debug_buff);
520 } 520 }
521 521
522 void gaim_signal_disconnect(void *handle, enum gaim_event which, void *func) { 522 void gaim_signal_disconnect(GModule *handle, enum gaim_event which, void *func) {
523 GList *c = callbacks; 523 GList *c = callbacks;
524 struct gaim_callback *g = NULL; 524 struct gaim_callback *g = NULL;
525 525
526 while (c) { 526 while (c) {
527 g = (struct gaim_callback *)c->data; 527 g = (struct gaim_callback *)c->data;
670 break; 670 break;
671 671
672 /* struct gaim_connection *, char * */ 672 /* struct gaim_connection *, char * */
673 case event_chat_join: 673 case event_chat_join:
674 case event_chat_leave: 674 case event_chat_leave:
675 {
676 void (*function)(struct gaim_connection *, char *, void *) =
677 g->function;
678 (*function)(arg1, arg2, g->data);
679 }
680 break;
681
682 /* char * */
683 case event_buddy_signon: 675 case event_buddy_signon:
684 case event_buddy_signoff: 676 case event_buddy_signoff:
685 case event_buddy_away: 677 case event_buddy_away:
686 case event_buddy_back: 678 case event_buddy_back:
687 case event_buddy_idle: 679 case event_buddy_idle:
688 case event_buddy_unidle: 680 case event_buddy_unidle:
681 {
682 void (*function)(struct gaim_connection *, char *, void *) =
683 g->function;
684 (*function)(arg1, arg2, g->data);
685 }
686 break;
687
688 /* char * */
689 case event_new_conversation: 689 case event_new_conversation:
690 { 690 {
691 void (*function)(char *, void *) = g->function; 691 void (*function)(char *, void *) = g->function;
692 (*function)(arg1, g->data); 692 (*function)(arg1, g->data);
693 } 693 }