Mercurial > pidgin
changeset 3563:e120097bbd72
[gaim-migrate @ 3658]
I made my perl script unloading not suck (as much). Now you may port your
perl scripts--use gaim.pl and PERL-HOWTO as references.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 28 Sep 2002 08:08:14 +0000 |
parents | de3bc24fff02 |
children | 83a54877f1ae |
files | plugins/PERL-HOWTO plugins/gaim.pl src/core.h src/gaimrc.c src/module.c src/perl.c src/prefs.c |
diffstat | 7 files changed, 162 insertions(+), 110 deletions(-) [+] |
line wrap: on
line diff
--- a/plugins/PERL-HOWTO Sat Sep 28 03:48:28 2002 +0000 +++ b/plugins/PERL-HOWTO Sat Sep 28 08:08:14 2002 +0000 @@ -42,7 +42,15 @@ Just like X-Chat. This is the first function your script should call. shutdownroutine is a function that will be called when the script gets unloaded (like when gaim gets closed). This function returns - gaim's version number. + gaim's version number. This function MUST use the same Name and Version + given in description()--the plugin won't work otherwise. This returns a + handle--you want to hold on to this. + + The handle is what Gaim will use to distinguish your script from any others + running. It's actually a string--the path to the script, but you'll probably + never need to know that. As long as you just hold on to it and don't change it + everything should work fine. You need it for GAIM::add_event_handler and + GAIM::add_timeout_handler. GAIM::get_info(integer, ...) This function returns different information based on the integer passed @@ -125,11 +133,12 @@ GAIM::print_to_chat(index, room, what) Room is actually an int. Read SIGNALS to find out why. -GAIM::add_event_handler(event, function) +GAIM::add_event_handler(handle, event, function) This is the most important of them all. This is basically exactly like - gaim_signal_connect for plugins. You pass which event you want to connect to - (a string with the same name as the events for plugins, see SIGNALS), and a - string with the name of the function you want called. Simple enough? + gaim_signal_connect for plugins. You pass the handle returned by GAIM::register, + which event you want to connect to (a string with the same name as the events for + plugins, see SIGNALS), and a string with the name of the function you want called. + Simple enough? When this is triggered, the arguments will be passed in @_ and are broken into a list. This is different from all previous versions of Gaim, where you @@ -150,11 +159,11 @@ calls "function" as its handler. The event handler must have been previously added with GAIM::add_event_handler. -GAIM::add_timeout_handler(integer, function, args) +GAIM::add_timeout_handler(handle, integer, function, args) This calls function after integer number of seconds. It only calls function once, so if you want to keep calling function, keep readding the handler. Args is a string that you'd like to have passed to your timeout handler; it's - optional. + optional. Handle is the handle returned by GAIM::register--it is not optional. GAIM::play_sound(int sound) Plays a sound using whatever method the user has selected. The argument is
--- a/plugins/gaim.pl Sat Sep 28 03:48:28 2002 +0000 +++ b/plugins/gaim.pl Sat Sep 28 08:08:14 2002 +0000 @@ -1,5 +1,12 @@ -GAIM::register("Example", "1.0", "goodbye", ""); +sub description { + my($a, $b, $c, $d, $e, $f) = @_; + ("Example", "1.0", "An example Gaim perl script that does nothing particularly useful:\n\t-Show a dialog on load\n\t-Set user idle for 6,000 seconds\n\t-Greets people signing on with \"Hello\"\n\t-Informs you when script has been loaded for one minute.", "Eric Warmenhoven <eric\@warmenhoven.org>", "http://gaim.sf.net", "/dev/null"); +} +$handle = GAIM::register("Example", "1.0", "goodbye", ""); + +GAIM::print("Perl Says", "Handle $handle"); + $ver = GAIM::get_info(0); @ids = GAIM::get_info(1); @@ -10,12 +17,11 @@ $msg .= "\n$nam using $pro"; } -GAIM::print("Perl Says", $msg); GAIM::command("idle", 6000); -GAIM::add_event_handler("event_buddy_signon", "echo_reply"); -GAIM::add_timeout_handler(60, "notify"); +GAIM::add_event_handler($handle, "event_buddy_signon", "echo_reply"); +GAIM::add_timeout_handler($handle, 60, "notify"); sub echo_reply { $index = $_[0]; @@ -31,8 +37,3 @@ GAIM::print("You Bastard!", "You killed Kenny!"); } -sub description { - my($a, $b, $c, $d, $e, $f) = @_; - ("Example", "1.0", "An example Gaim perl script that does nothing particularly useful:\n\t-Show a dialog on load\n\t-Set user idle for 6,000 seconds\n\t-Greets people signing on with \"Hello\"\n\t-Informs you when script has been loaded for one minute.", "Eric Warmenhoven <eric\@warmenhoven.org>", "http://gaim.sf.net", "/dev/null"); - } -
--- a/src/core.h Sat Sep 28 03:48:28 2002 +0000 +++ b/src/core.h Sat Sep 28 08:08:14 2002 +0000 @@ -131,6 +131,7 @@ void *handle; gchar path[128]; struct gaim_plugin_description desc; + gchar error[128]; }; #ifdef GAIM_PLUGINS
--- a/src/gaimrc.c Sat Sep 28 03:48:28 2002 +0000 +++ b/src/gaimrc.c Sat Sep 28 08:08:14 2002 +0000 @@ -400,8 +400,8 @@ p = (struct gaim_plugin *)pl->data; - path = escape_text2(g_module_name(p->handle)); - + path = escape_text2(p->path); + fprintf(f, "\tplugin { %s }\n", path); free(path);
--- a/src/module.c Sat Sep 28 03:48:28 2002 +0000 +++ b/src/module.c Sat Sep 28 08:08:14 2002 +0000 @@ -136,7 +136,7 @@ #endif #ifdef USE_PERL if (is_so_file(file, ".pl")) { - path = g_build_filename(LIBDIR, file, NULL); + path = g_build_filename(probedirs[l], file, NULL); plug = probe_perl(path); if (plug) probed_plugins = g_list_append(probed_plugins, plug); @@ -159,7 +159,7 @@ GList *c = plugins; GList *p = probed_plugins; char *(*gaim_plugin_init)(GModule *); - char *error, *retval, *tmp; + char *error, *retval; gboolean newplug = FALSE; if (!g_module_supported()) @@ -167,6 +167,10 @@ if (!filename || !strlen(filename)) return NULL; + if (is_so_file(filename, ".pl")) { + return perl_load_file(filename); + } + while (filename && p) { plug = (struct gaim_plugin *)p->data; if (!strcmp(filename, plug->path)) @@ -190,21 +194,18 @@ if (!plug->handle) { error = (char *)g_module_error(); plug->handle = NULL; - tmp = plug->desc.description; - plug->desc.description = g_strdup_printf("<span weight=\"bold\" foreground=\"red\">%s</span>\n\n%s", error, tmp); - g_free(tmp); + g_snprintf(plug->error, sizeof(plug->error), error); return NULL; } if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) { g_module_close(plug->handle); plug->handle = NULL; - tmp = plug->desc.description; - plug->desc.description = g_strdup_printf("<span foreground=\"red\">%s</span>\n\n%s", g_module_error(), tmp); - g_free(tmp); + g_snprintf(plug->error, sizeof(plug->error), error); return NULL; } + plug->error[0] = '\0'; retval = gaim_plugin_init(plug->handle); debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL"); if (retval) { @@ -632,8 +633,10 @@ while (c) { p = (struct gaim_plugin *)c->data; - if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) - gaim_plugin_remove(); + if (p->type == plugin) { + if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove)) + gaim_plugin_remove(); + } g_free(p); c = c->next; }
--- a/src/perl.c Sat Sep 28 03:48:28 2002 +0000 +++ b/src/perl.c Sat Sep 28 08:08:14 2002 +0000 @@ -68,19 +68,20 @@ char *name; char *version; char *shutdowncallback; /* bleh */ + struct gaim_plugin *plug; }; struct _perl_event_handlers { char *event_type; char *handler_name; - char *handle; + struct gaim_plugin *plug; }; struct _perl_timeout_handlers { char *handler_name; char *handler_args; gint iotag; - char *handle; + struct gaim_plugin *plug; }; static GList *perl_list = NULL; /* should probably extern this at some point */ @@ -203,8 +204,6 @@ } -/* This function is so incredibly broken and should never, ever, ever - be trusted to work */ void perl_unload_file(struct gaim_plugin *plug) { struct perlscript *scp = NULL; struct _perl_timeout_handlers *thn; @@ -215,29 +214,24 @@ debug_printf("Unloading %s\n", plug->handle); while (pl) { scp = pl->data; - /* This is so broken */ - if (!strcmp(scp->name, plug->desc.name) && - !strcmp(scp->version, plug->desc.version)) + if (scp->plug == plug) { + perl_list = g_list_remove(perl_list, scp); + if (scp->shutdowncallback[0]) + execute_perl(scp->shutdowncallback, ""); + perl_list = g_list_remove(perl_list, scp); + g_free(scp->name); + g_free(scp->version); + g_free(scp->shutdowncallback); + g_free(scp); break; - pl = pl->next; - scp = NULL; - } - if (scp) { - perl_list = g_list_remove(perl_list, scp); - if (scp->shutdowncallback[0]) - execute_perl(scp->shutdowncallback, ""); - perl_list = g_list_remove(perl_list, scp); - g_free(scp->name); - g_free(scp->version); - g_free(scp->shutdowncallback); - g_free(scp); + } } pl = perl_timeout_handlers; while (pl) { thn = pl->data; - if (thn && thn->handle == plug->handle) { - g_list_remove(perl_timeout_handlers, thn); + if (thn && thn->plug == plug) { + perl_timeout_handlers = g_list_remove(perl_timeout_handlers, thn); g_source_remove(thn->iotag); g_free(thn->handler_args); g_free(thn->handler_name); @@ -249,7 +243,7 @@ pl = perl_event_handlers; while (pl) { ehn = pl->data; - if (ehn && ehn->handle == plug->handle) { + if (ehn && ehn->plug == plug) { perl_event_handlers = g_list_remove(perl_event_handlers, ehn); g_free(ehn->event_type); g_free(ehn->handler_name); @@ -259,15 +253,17 @@ } plug->handle=NULL; + plugins = g_list_remove(plugins, plug); + save_prefs(); } int perl_load_file(char *script_name) { struct gaim_plugin *plug; GList *p = probed_plugins; - GList *e = perl_event_handlers; - GList *t = perl_timeout_handlers; - int num_e, num_t, ret; + GList *s; + struct perlscript *scp; + int ret; if (my_perl == NULL) perl_init(); @@ -282,36 +278,35 @@ if (!plug) { probe_perl(script_name); } - + plug->handle = plug->path; - - /* This is such a terrible hack-- if I weren't tired and annoyed - * with perl, I'm sure I wouldn't even be considering this. */ - num_e=g_list_length(e); - num_t=g_list_length(t); + plugins = g_list_append(plugins, plug); ret = execute_perl("load_n_eval", script_name); - t = g_list_nth(perl_timeout_handlers, num_t++); - while (t) { - struct _perl_timeout_handlers *h = t->data; - h->handle = plug->handle; - t = t->next; + s = perl_list; + while (s) { + scp = s->data; + + if (!strcmp(scp->name, plug->desc.name) && + !strcmp(scp->version, plug->desc.version)) + break; + s = s->next; } - e = g_list_nth(perl_event_handlers, num_e++); - while (e) { - struct _perl_event_handlers *h = e->data; - h->handle = plug->handle; - e = e->next; + if (!s) { + g_snprintf(plug->error, sizeof(plug->error), _("GAIM::register not called with proper arguments. Consult PERL-HOWTO.")); + return 0; } + + plug->error[0] = '\0'; return ret; } struct gaim_plugin *probe_perl(const char *filename) { /* XXX This woulld be much faster if I didn't create a new - * PerlInterpreter every time I did probed a plugin */ + * PerlInterpreter every time I probed a plugin */ PerlInterpreter *prober = perl_alloc(); struct gaim_plugin * plug = NULL; @@ -328,7 +323,6 @@ count = perl_call_pv("description", G_NOARGS | G_ARRAY | G_EVAL); SPAGAIN; - debug_printf("desc: %d char: %d count: %d\n", sizeof(struct gaim_plugin_description), sizeof(char*), count); if (count == (sizeof(struct gaim_plugin_description) - sizeof(int)) / sizeof(char*)) { plug = g_new0(struct gaim_plugin, 1); plug->type = perl_script; @@ -449,6 +443,9 @@ char *name, *ver, *callback, *unused; /* exactly like X-Chat, eh? :) */ unsigned int junk; struct perlscript *scp; + struct gaim_plugin *plug; + GList *pl = plugins; + dXSARGS; items = 0; @@ -457,13 +454,25 @@ callback = SvPV (ST (2), junk); unused = SvPV (ST (3), junk); - scp = g_new0(struct perlscript, 1); - scp->name = g_strdup(name); - scp->version = g_strdup(ver); - scp->shutdowncallback = g_strdup(callback); - perl_list = g_list_append(perl_list, scp); + while (pl) { + plug = pl->data; + + if (!strcmp(name, plug->desc.name) && + !strcmp(ver, plug->desc.version)) { + break; + } + pl = pl->next; + } - XST_mPV (0, VERSION); + if (plug) { + scp = g_new0(struct perlscript, 1); + scp->name = g_strdup(name); + scp->version = g_strdup(ver); + scp->shutdowncallback = g_strdup(callback); + scp->plug = plug; + perl_list = g_list_append(perl_list, scp); + } + XST_mPV (0, plug->path); XSRETURN (1); } @@ -963,14 +972,31 @@ { unsigned int junk; struct _perl_event_handlers *handler; + char *handle; + struct gaim_plugin *plug; + GList *p = plugins; dXSARGS; items = 0; + + handle = SvPV(ST(0), junk); + while (p) { + plug = p->data; + if (!strcmp(handle, plug->path)) + break; + p = p->next; + } - handler = g_new0(struct _perl_event_handlers, 1); - handler->event_type = g_strdup(SvPV(ST(0), junk)); - handler->handler_name = g_strdup(SvPV(ST(1), junk)); - perl_event_handlers = g_list_append(perl_event_handlers, handler); - debug_printf("registered perl event handler for %s\n", handler->event_type); + if (p) { + handler = g_new0(struct _perl_event_handlers, 1); + handler->event_type = g_strdup(SvPV(ST(1), junk)); + handler->handler_name = g_strdup(SvPV(ST(2), junk)); + handler->plug = plug; + perl_event_handlers = g_list_append(perl_event_handlers, handler); + debug_printf("registered perl event handler for %s\n", handler->event_type); + } else { + debug_printf("Invalid handle (%s) registering perl event handler\n", handle); + } + XSRETURN_EMPTY; } @@ -1015,16 +1041,33 @@ unsigned int junk; long timeout; struct _perl_timeout_handlers *handler; + char *handle; + struct gaim_plugin *plug; + GList *p = plugins; + dXSARGS; items = 0; + + handle = SvPV(ST(0), junk); + while (p) { + plug = p->data; + if (!strcmp(handle, plug->path)) + break; + p = p->next; + } - handler = g_new0(struct _perl_timeout_handlers, 1); - timeout = 1000 * SvIV(ST(0)); - debug_printf("Adding timeout for %d seconds.\n", timeout/1000); - handler->handler_name = g_strdup(SvPV(ST(1), junk)); - handler->handler_args = g_strdup(SvPV(ST(2), junk)); - perl_timeout_handlers = g_list_append(perl_timeout_handlers, handler); - handler->iotag = g_timeout_add(timeout, perl_timeout, handler); + if (p) { + handler = g_new0(struct _perl_timeout_handlers, 1); + timeout = 1000 * SvIV(ST(1)); + debug_printf("Adding timeout for %d seconds.\n", timeout/1000); + handler->plug = plug; + handler->handler_name = g_strdup(SvPV(ST(2), junk)); + handler->handler_args = g_strdup(SvPV(ST(3), junk)); + perl_timeout_handlers = g_list_append(perl_timeout_handlers, handler); + handler->iotag = g_timeout_add(timeout, perl_timeout, handler); + } else { + debug_printf("Invalid handle (%s) in adding perl timeout handler.", handle); + } XSRETURN_EMPTY; } @@ -1046,21 +1089,5 @@ perl_init(); } -extern void list_perl_scripts() -{ - GList *s = perl_list; - struct perlscript *p; - char buf[BUF_LONG * 4]; - int at = 0; - - at += g_snprintf(buf + at, sizeof(buf) - at, "Loaded scripts:\n"); - while (s) { - p = (struct perlscript *)s->data; - at += g_snprintf(buf + at, sizeof(buf) - at, "%s\n", p->name); - s = s->next; - } - - do_error_dialog(buf, NULL, GAIM_INFO); -} #endif /* USE_PERL */
--- a/src/prefs.c Sat Sep 28 03:48:28 2002 +0000 +++ b/src/prefs.c Sat Sep 28 08:08:14 2002 +0000 @@ -861,8 +861,13 @@ gtk_tree_model_get_value (model, &iter, 2, &val); plug = g_value_get_pointer(&val); - g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n%s"), - plug->desc.name, plug->desc.version, plug->desc.description); + if (plug->error[0]) + g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n" + "<span weight=\"bold\" color=\"red\">%s</span>\n\n" + "%s"), plug->desc.name, plug->desc.version, plug->error, plug->desc.description); + else + g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n" + "%s"), plug->desc.name, plug->desc.version, plug->desc.description); gtk_label_set_markup(GTK_LABEL(plugin_description), buf); g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n" "<span weight=\"bold\">Written by:</span>\t%s\n" @@ -915,10 +920,16 @@ {} #endif gdk_window_set_cursor(prefs->window, NULL); - + if (plug->error[0]) + g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n" + "<span weight=\"bold\" color=\"red\">%s</span>\n\n" + "%s"), plug->desc.name, plug->desc.version, plug->error, plug->desc.description); + else + g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n" + "%s"), plug->desc.name, plug->desc.version, plug->desc.description); + gtk_label_set_markup(GTK_LABEL(plugin_description), buf); gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, plug->handle, -1); - g_snprintf(buf, sizeof(buf), _("<span size=\"larger\">%s %s</span>\n\n%s"), - plug->desc.name, plug->desc.version, plug->desc.description); + gtk_label_set_markup(GTK_LABEL(plugin_description), buf); gtk_tree_path_free(path); }