| 1 #include "perl-common.h" |
|
| 2 #include "perl-handlers.h" |
|
| 3 |
|
| 4 #include "debug.h" |
|
| 5 #include "signals.h" |
|
| 6 |
|
| 7 extern PerlInterpreter *my_perl; |
|
| 8 static GList *cmd_handlers = NULL; |
|
| 9 static GList *signal_handlers = NULL; |
|
| 10 static GList *timeout_handlers = NULL; |
|
| 11 |
|
| 12 /* perl < 5.8.0 doesn't define PERL_MAGIC_ext */ |
|
| 13 #ifndef PERL_MAGIC_ext |
|
| 14 #define PERL_MAGIC_ext '~' |
|
| 15 #endif |
|
| 16 |
|
| 17 void |
|
| 18 gaim_perl_plugin_action_cb(GaimPluginAction *action) |
|
| 19 { |
|
| 20 SV **callback; |
|
| 21 HV *hv = NULL; |
|
| 22 gchar *hvname; |
|
| 23 GaimPlugin *plugin; |
|
| 24 GaimPerlScript *gps; |
|
| 25 dSP; |
|
| 26 |
|
| 27 plugin = action->plugin; |
|
| 28 gps = (GaimPerlScript *)plugin->info->extra_info; |
|
| 29 hvname = g_strdup_printf("%s::plugin_actions", gps->package); |
|
| 30 hv = get_hv(hvname, FALSE); |
|
| 31 g_free(hvname); |
|
| 32 |
|
| 33 if (hv == NULL) |
|
| 34 croak("No plugin_actions hash found in \"%s\" plugin.", gaim_plugin_get_name(plugin)); |
|
| 35 |
|
| 36 ENTER; |
|
| 37 SAVETMPS; |
|
| 38 |
|
| 39 callback = hv_fetch(hv, action->label, strlen(action->label), 0); |
|
| 40 |
|
| 41 if (callback == NULL || *callback == NULL) |
|
| 42 croak("No plugin_action function named \"%s\" in \"%s\" plugin.", action->label, gaim_plugin_get_name(plugin)); |
|
| 43 |
|
| 44 PUSHMARK(sp); |
|
| 45 XPUSHs(gaim_perl_bless_object(gps->plugin, "Gaim::Plugin")); |
|
| 46 PUTBACK; |
|
| 47 |
|
| 48 call_sv(*callback, G_VOID | G_DISCARD); |
|
| 49 SPAGAIN; |
|
| 50 |
|
| 51 PUTBACK; |
|
| 52 FREETMPS; |
|
| 53 LEAVE; |
|
| 54 } |
|
| 55 |
|
| 56 GList * |
|
| 57 gaim_perl_plugin_actions(GaimPlugin *plugin, gpointer context) |
|
| 58 { |
|
| 59 GList *l = NULL; |
|
| 60 GaimPerlScript *gps; |
|
| 61 int i = 0, count = 0; |
|
| 62 dSP; |
|
| 63 |
|
| 64 gps = (GaimPerlScript *)plugin->info->extra_info; |
|
| 65 |
|
| 66 ENTER; |
|
| 67 SAVETMPS; |
|
| 68 |
|
| 69 PUSHMARK(SP); |
|
| 70 XPUSHs(sv_2mortal(gaim_perl_bless_object(plugin, "Gaim::Plugin"))); |
|
| 71 /* XXX This *will* cease working correctly if context gets changed to |
|
| 72 * ever be able to hold anything other than a GaimConnection */ |
|
| 73 if (context != NULL) |
|
| 74 XPUSHs(sv_2mortal(gaim_perl_bless_object(context, "Gaim::Connection"))); |
|
| 75 else |
|
| 76 XPUSHs(&PL_sv_undef); |
|
| 77 PUTBACK; |
|
| 78 |
|
| 79 count = call_pv(gps->plugin_action_sub, G_ARRAY); |
|
| 80 |
|
| 81 SPAGAIN; |
|
| 82 |
|
| 83 if (count == 0) |
|
| 84 croak("The plugin_actions sub didn't return anything.\n"); |
|
| 85 |
|
| 86 for (i = 0; i < count; i++) { |
|
| 87 SV *sv; |
|
| 88 gchar *label; |
|
| 89 GaimPluginAction *act = NULL; |
|
| 90 |
|
| 91 sv = POPs; |
|
| 92 label = SvPV_nolen(sv); |
|
| 93 /* XXX I think this leaks, but doing it without the strdup |
|
| 94 * just showed garbage */ |
|
| 95 act = gaim_plugin_action_new(g_strdup(label), gaim_perl_plugin_action_cb); |
|
| 96 l = g_list_append(l, act); |
|
| 97 } |
|
| 98 |
|
| 99 PUTBACK; |
|
| 100 FREETMPS; |
|
| 101 LEAVE; |
|
| 102 |
|
| 103 return l; |
|
| 104 } |
|
| 105 |
|
| 106 GtkWidget * |
|
| 107 gaim_perl_gtk_get_plugin_frame(GaimPlugin *plugin) |
|
| 108 { |
|
| 109 SV * sv; |
|
| 110 int count; |
|
| 111 MAGIC *mg; |
|
| 112 GtkWidget *ret; |
|
| 113 GaimPerlScript *gps; |
|
| 114 dSP; |
|
| 115 |
|
| 116 gps = (GaimPerlScript *)plugin->info->extra_info; |
|
| 117 |
|
| 118 ENTER; |
|
| 119 SAVETMPS; |
|
| 120 |
|
| 121 count = call_pv(gps->gtk_prefs_sub, G_SCALAR | G_NOARGS); |
|
| 122 if (count != 1) |
|
| 123 croak("call_pv: Did not return the correct number of values.\n"); |
|
| 124 |
|
| 125 /* the frame was created in a perl sub and is returned */ |
|
| 126 SPAGAIN; |
|
| 127 |
|
| 128 /* We have a Gtk2::Frame on top of the stack */ |
|
| 129 sv = POPs; |
|
| 130 |
|
| 131 /* The magic field hides the pointer to the actual GtkWidget */ |
|
| 132 mg = mg_find(SvRV(sv), PERL_MAGIC_ext); |
|
| 133 ret = (GtkWidget *)mg->mg_ptr; |
|
| 134 |
|
| 135 PUTBACK; |
|
| 136 FREETMPS; |
|
| 137 LEAVE; |
|
| 138 |
|
| 139 return ret; |
|
| 140 } |
|
| 141 |
|
| 142 GaimPluginPrefFrame * |
|
| 143 gaim_perl_get_plugin_frame(GaimPlugin *plugin) |
|
| 144 { |
|
| 145 /* Sets up the Perl Stack for our call back into the script to run the |
|
| 146 * plugin_pref... sub */ |
|
| 147 int count; |
|
| 148 GaimPerlScript *gps; |
|
| 149 GaimPluginPrefFrame *ret_frame; |
|
| 150 dSP; |
|
| 151 |
|
| 152 gps = (GaimPerlScript *)plugin->info->extra_info; |
|
| 153 |
|
| 154 ENTER; |
|
| 155 SAVETMPS; |
|
| 156 /* Some perl magic to run perl_plugin_pref_frame_SV perl sub and |
|
| 157 * return the frame */ |
|
| 158 PUSHMARK(SP); |
|
| 159 PUTBACK; |
|
| 160 |
|
| 161 count = call_pv(gps->prefs_sub, G_SCALAR | G_NOARGS); |
|
| 162 |
|
| 163 SPAGAIN; |
|
| 164 |
|
| 165 if (count != 1) |
|
| 166 croak("call_pv: Did not return the correct number of values.\n"); |
|
| 167 /* the frame was created in a perl sub and is returned */ |
|
| 168 ret_frame = (GaimPluginPrefFrame *)gaim_perl_ref_object(POPs); |
|
| 169 |
|
| 170 /* Tidy up the Perl stack */ |
|
| 171 PUTBACK; |
|
| 172 FREETMPS; |
|
| 173 LEAVE; |
|
| 174 |
|
| 175 return ret_frame; |
|
| 176 } |
|
| 177 |
|
| 178 static void |
|
| 179 destroy_timeout_handler(GaimPerlTimeoutHandler *handler) |
|
| 180 { |
|
| 181 timeout_handlers = g_list_remove(timeout_handlers, handler); |
|
| 182 |
|
| 183 if (handler->callback != NULL) |
|
| 184 SvREFCNT_dec(handler->callback); |
|
| 185 |
|
| 186 if (handler->data != NULL) |
|
| 187 SvREFCNT_dec(handler->data); |
|
| 188 |
|
| 189 g_free(handler); |
|
| 190 } |
|
| 191 |
|
| 192 static void |
|
| 193 destroy_signal_handler(GaimPerlSignalHandler *handler) |
|
| 194 { |
|
| 195 signal_handlers = g_list_remove(signal_handlers, handler); |
|
| 196 |
|
| 197 if (handler->callback != NULL) |
|
| 198 SvREFCNT_dec(handler->callback); |
|
| 199 |
|
| 200 if (handler->data != NULL) |
|
| 201 SvREFCNT_dec(handler->data); |
|
| 202 |
|
| 203 g_free(handler->signal); |
|
| 204 g_free(handler); |
|
| 205 } |
|
| 206 |
|
| 207 static int |
|
| 208 perl_timeout_cb(gpointer data) |
|
| 209 { |
|
| 210 GaimPerlTimeoutHandler *handler = (GaimPerlTimeoutHandler *)data; |
|
| 211 |
|
| 212 dSP; |
|
| 213 ENTER; |
|
| 214 SAVETMPS; |
|
| 215 PUSHMARK(sp); |
|
| 216 XPUSHs((SV *)handler->data); |
|
| 217 PUTBACK; |
|
| 218 call_sv(handler->callback, G_EVAL | G_SCALAR); |
|
| 219 SPAGAIN; |
|
| 220 |
|
| 221 PUTBACK; |
|
| 222 FREETMPS; |
|
| 223 LEAVE; |
|
| 224 |
|
| 225 destroy_timeout_handler(handler); |
|
| 226 |
|
| 227 return 0; |
|
| 228 } |
|
| 229 |
|
| 230 typedef void *DATATYPE; |
|
| 231 |
|
| 232 static void * |
|
| 233 perl_signal_cb(va_list args, void *data) |
|
| 234 { |
|
| 235 GaimPerlSignalHandler *handler = (GaimPerlSignalHandler *)data; |
|
| 236 void *ret_val = NULL; |
|
| 237 int i; |
|
| 238 int count; |
|
| 239 int value_count; |
|
| 240 GaimValue *ret_value, **values; |
|
| 241 SV **sv_args; |
|
| 242 DATATYPE **copy_args; |
|
| 243 STRLEN na; |
|
| 244 |
|
| 245 dSP; |
|
| 246 ENTER; |
|
| 247 SAVETMPS; |
|
| 248 PUSHMARK(sp); |
|
| 249 |
|
| 250 gaim_signal_get_values(handler->instance, handler->signal, |
|
| 251 &ret_value, &value_count, &values); |
|
| 252 |
|
| 253 sv_args = g_new(SV *, value_count); |
|
| 254 copy_args = g_new(void **, value_count); |
|
| 255 |
|
| 256 for (i = 0; i < value_count; i++) { |
|
| 257 sv_args[i] = gaim_perl_sv_from_vargs(values[i], |
|
| 258 (va_list*)&args, |
|
| 259 ©_args[i]); |
|
| 260 |
|
| 261 XPUSHs(sv_args[i]); |
|
| 262 } |
|
| 263 |
|
| 264 XPUSHs((SV *)handler->data); |
|
| 265 |
|
| 266 PUTBACK; |
|
| 267 |
|
| 268 if (ret_value != NULL) { |
|
| 269 count = call_sv(handler->callback, G_EVAL | G_SCALAR); |
|
| 270 |
|
| 271 SPAGAIN; |
|
| 272 |
|
| 273 if (count != 1) |
|
| 274 croak("Uh oh! call_sv returned %i != 1", i); |
|
| 275 else |
|
| 276 ret_val = gaim_perl_data_from_sv(ret_value, POPs); |
|
| 277 } else { |
|
| 278 call_sv(handler->callback, G_SCALAR); |
|
| 279 |
|
| 280 SPAGAIN; |
|
| 281 } |
|
| 282 |
|
| 283 if (SvTRUE(ERRSV)) { |
|
| 284 gaim_debug_error("perl", |
|
| 285 "Perl function exited abnormally: %s\n", |
|
| 286 SvPV(ERRSV, na)); |
|
| 287 } |
|
| 288 |
|
| 289 /* See if any parameters changed. */ |
|
| 290 for (i = 0; i < value_count; i++) { |
|
| 291 if (gaim_value_is_outgoing(values[i])) { |
|
| 292 switch (gaim_value_get_type(values[i])) { |
|
| 293 case GAIM_TYPE_BOOLEAN: |
|
| 294 *((gboolean *)copy_args[i]) = SvIV(sv_args[i]); |
|
| 295 break; |
|
| 296 |
|
| 297 case GAIM_TYPE_INT: |
|
| 298 *((int *)copy_args[i]) = SvIV(sv_args[i]); |
|
| 299 break; |
|
| 300 |
|
| 301 case GAIM_TYPE_UINT: |
|
| 302 *((unsigned int *)copy_args[i]) = SvUV(sv_args[i]); |
|
| 303 break; |
|
| 304 |
|
| 305 case GAIM_TYPE_LONG: |
|
| 306 *((long *)copy_args[i]) = SvIV(sv_args[i]); |
|
| 307 break; |
|
| 308 |
|
| 309 case GAIM_TYPE_ULONG: |
|
| 310 *((unsigned long *)copy_args[i]) = SvUV(sv_args[i]); |
|
| 311 break; |
|
| 312 |
|
| 313 case GAIM_TYPE_INT64: |
|
| 314 *((gint64 *)copy_args[i]) = SvIV(sv_args[i]); |
|
| 315 break; |
|
| 316 |
|
| 317 case GAIM_TYPE_UINT64: |
|
| 318 *((guint64 *)copy_args[i]) = SvUV(sv_args[i]); |
|
| 319 break; |
|
| 320 |
|
| 321 case GAIM_TYPE_STRING: |
|
| 322 if (strcmp(*((char **)copy_args[i]), SvPVX(sv_args[i]))) { |
|
| 323 g_free(*((char **)copy_args[i])); |
|
| 324 *((char **)copy_args[i]) = |
|
| 325 g_strdup(SvPV(sv_args[i], na)); |
|
| 326 } |
|
| 327 break; |
|
| 328 |
|
| 329 case GAIM_TYPE_POINTER: |
|
| 330 *((void **)copy_args[i]) = (void *)SvIV(sv_args[i]); |
|
| 331 break; |
|
| 332 |
|
| 333 case GAIM_TYPE_BOXED: |
|
| 334 *((void **)copy_args[i]) = (void *)SvIV(sv_args[i]); |
|
| 335 break; |
|
| 336 |
|
| 337 default: |
|
| 338 break; |
|
| 339 } |
|
| 340 |
|
| 341 #if 0 |
|
| 342 *((void **)copy_args[i]) = gaim_perl_data_from_sv(values[i], |
|
| 343 sv_args[i]); |
|
| 344 #endif |
|
| 345 } |
|
| 346 } |
|
| 347 |
|
| 348 PUTBACK; |
|
| 349 FREETMPS; |
|
| 350 LEAVE; |
|
| 351 |
|
| 352 g_free(sv_args); |
|
| 353 g_free(copy_args); |
|
| 354 |
|
| 355 gaim_debug_misc("perl", "ret_val = %p\n", ret_val); |
|
| 356 |
|
| 357 return ret_val; |
|
| 358 } |
|
| 359 |
|
| 360 static GaimPerlSignalHandler * |
|
| 361 find_signal_handler(GaimPlugin *plugin, void *instance, const char *signal) |
|
| 362 { |
|
| 363 GaimPerlSignalHandler *handler; |
|
| 364 GList *l; |
|
| 365 |
|
| 366 for (l = signal_handlers; l != NULL; l = l->next) { |
|
| 367 handler = (GaimPerlSignalHandler *)l->data; |
|
| 368 |
|
| 369 if (handler->plugin == plugin && |
|
| 370 handler->instance == instance && |
|
| 371 !strcmp(handler->signal, signal)) { |
|
| 372 return handler; |
|
| 373 } |
|
| 374 } |
|
| 375 |
|
| 376 return NULL; |
|
| 377 } |
|
| 378 |
|
| 379 void |
|
| 380 gaim_perl_timeout_add(GaimPlugin *plugin, int seconds, SV *callback, SV *data) |
|
| 381 { |
|
| 382 GaimPerlTimeoutHandler *handler; |
|
| 383 |
|
| 384 if (plugin == NULL) { |
|
| 385 croak("Invalid handle in adding perl timeout handler.\n"); |
|
| 386 return; |
|
| 387 } |
|
| 388 |
|
| 389 handler = g_new0(GaimPerlTimeoutHandler, 1); |
|
| 390 |
|
| 391 handler->plugin = plugin; |
|
| 392 handler->callback = (callback != NULL && callback != &PL_sv_undef |
|
| 393 ? newSVsv(callback) : NULL); |
|
| 394 handler->data = (data != NULL && data != &PL_sv_undef |
|
| 395 ? newSVsv(data) : NULL); |
|
| 396 |
|
| 397 timeout_handlers = g_list_append(timeout_handlers, handler); |
|
| 398 |
|
| 399 handler->iotag = g_timeout_add(seconds * 1000, perl_timeout_cb, handler); |
|
| 400 } |
|
| 401 |
|
| 402 void |
|
| 403 gaim_perl_timeout_clear_for_plugin(GaimPlugin *plugin) |
|
| 404 { |
|
| 405 GaimPerlTimeoutHandler *handler; |
|
| 406 GList *l, *l_next; |
|
| 407 |
|
| 408 for (l = timeout_handlers; l != NULL; l = l_next) { |
|
| 409 l_next = l->next; |
|
| 410 |
|
| 411 handler = (GaimPerlTimeoutHandler *)l->data; |
|
| 412 |
|
| 413 if (handler->plugin == plugin) |
|
| 414 destroy_timeout_handler(handler); |
|
| 415 } |
|
| 416 } |
|
| 417 |
|
| 418 void |
|
| 419 gaim_perl_timeout_clear(void) |
|
| 420 { |
|
| 421 while (timeout_handlers != NULL) |
|
| 422 destroy_timeout_handler(timeout_handlers->data); |
|
| 423 } |
|
| 424 |
|
| 425 void |
|
| 426 gaim_perl_signal_connect(GaimPlugin *plugin, void *instance, |
|
| 427 const char *signal, SV *callback, SV *data) |
|
| 428 { |
|
| 429 GaimPerlSignalHandler *handler; |
|
| 430 |
|
| 431 handler = g_new0(GaimPerlSignalHandler, 1); |
|
| 432 handler->plugin = plugin; |
|
| 433 handler->instance = instance; |
|
| 434 handler->signal = g_strdup(signal); |
|
| 435 handler->callback = (callback != NULL && |
|
| 436 callback != &PL_sv_undef ? newSVsv(callback) |
|
| 437 : NULL); |
|
| 438 handler->data = (data != NULL && |
|
| 439 data != &PL_sv_undef ? newSVsv(data) : NULL); |
|
| 440 |
|
| 441 signal_handlers = g_list_append(signal_handlers, handler); |
|
| 442 |
|
| 443 gaim_signal_connect_vargs(instance, signal, plugin, |
|
| 444 GAIM_CALLBACK(perl_signal_cb), handler); |
|
| 445 } |
|
| 446 |
|
| 447 void |
|
| 448 gaim_perl_signal_disconnect(GaimPlugin *plugin, void *instance, |
|
| 449 const char *signal) |
|
| 450 { |
|
| 451 GaimPerlSignalHandler *handler; |
|
| 452 |
|
| 453 handler = find_signal_handler(plugin, instance, signal); |
|
| 454 |
|
| 455 if (handler == NULL) { |
|
| 456 croak("Invalid signal handler information in " |
|
| 457 "disconnecting a perl signal handler.\n"); |
|
| 458 return; |
|
| 459 } |
|
| 460 |
|
| 461 destroy_signal_handler(handler); |
|
| 462 } |
|
| 463 |
|
| 464 void |
|
| 465 gaim_perl_signal_clear_for_plugin(GaimPlugin *plugin) |
|
| 466 { |
|
| 467 GaimPerlSignalHandler *handler; |
|
| 468 GList *l, *l_next; |
|
| 469 |
|
| 470 for (l = signal_handlers; l != NULL; l = l_next) { |
|
| 471 l_next = l->next; |
|
| 472 |
|
| 473 handler = (GaimPerlSignalHandler *)l->data; |
|
| 474 |
|
| 475 if (handler->plugin == plugin) |
|
| 476 destroy_signal_handler(handler); |
|
| 477 } |
|
| 478 } |
|
| 479 |
|
| 480 void |
|
| 481 gaim_perl_signal_clear(void) |
|
| 482 { |
|
| 483 while (signal_handlers != NULL) |
|
| 484 destroy_signal_handler(signal_handlers->data); |
|
| 485 } |
|
| 486 |
|
| 487 static GaimCmdRet |
|
| 488 perl_cmd_cb(GaimConversation *conv, const gchar *command, |
|
| 489 gchar **args, gchar **error, void *data) |
|
| 490 { |
|
| 491 int i = 0, count, ret_value = GAIM_CMD_RET_OK; |
|
| 492 SV *cmdSV, *tmpSV, *convSV; |
|
| 493 GaimPerlCmdHandler *handler = (GaimPerlCmdHandler *)data; |
|
| 494 |
|
| 495 dSP; |
|
| 496 ENTER; |
|
| 497 SAVETMPS; |
|
| 498 PUSHMARK(SP); |
|
| 499 |
|
| 500 /* Push the conversation onto the perl stack */ |
|
| 501 convSV = sv_2mortal(gaim_perl_bless_object(conv, "Gaim::Conversation")); |
|
| 502 XPUSHs(convSV); |
|
| 503 |
|
| 504 /* Push the command string onto the perl stack */ |
|
| 505 cmdSV = newSVpv(command, 0); |
|
| 506 cmdSV = sv_2mortal(cmdSV); |
|
| 507 XPUSHs(cmdSV); |
|
| 508 |
|
| 509 /* Push the data onto the perl stack */ |
|
| 510 XPUSHs((SV *)handler->data); |
|
| 511 |
|
| 512 /* Push any arguments we may have */ |
|
| 513 for (i = 0; args[i] != NULL; i++) { |
|
| 514 /* XXX The mortality of these created SV's should prevent |
|
| 515 * memory issues, if I read/understood everything correctly... |
|
| 516 */ |
|
| 517 tmpSV = newSVpv(args[i], 0); |
|
| 518 tmpSV = sv_2mortal(tmpSV); |
|
| 519 XPUSHs(tmpSV); |
|
| 520 } |
|
| 521 |
|
| 522 PUTBACK; |
|
| 523 count = call_sv(handler->callback, G_EVAL|G_SCALAR); |
|
| 524 |
|
| 525 if (count != 1) |
|
| 526 croak("call_sv: Did not return the correct number of values.\n"); |
|
| 527 |
|
| 528 SPAGAIN; |
|
| 529 |
|
| 530 ret_value = POPi; |
|
| 531 |
|
| 532 PUTBACK; |
|
| 533 FREETMPS; |
|
| 534 LEAVE; |
|
| 535 |
|
| 536 return ret_value; |
|
| 537 } |
|
| 538 |
|
| 539 GaimCmdId |
|
| 540 gaim_perl_cmd_register(GaimPlugin *plugin, const gchar *command, |
|
| 541 const gchar *args, GaimCmdPriority priority, |
|
| 542 GaimCmdFlag flag, const gchar *prpl_id, SV *callback, |
|
| 543 const gchar *helpstr, SV *data) |
|
| 544 { |
|
| 545 GaimPerlCmdHandler *handler; |
|
| 546 |
|
| 547 handler = g_new0(GaimPerlCmdHandler, 1); |
|
| 548 handler->plugin = plugin; |
|
| 549 handler->cmd = g_strdup(command); |
|
| 550 handler->prpl_id = g_strdup(prpl_id); |
|
| 551 |
|
| 552 if (callback != NULL && callback != &PL_sv_undef) |
|
| 553 handler->callback = newSVsv(callback); |
|
| 554 else |
|
| 555 handler->callback = NULL; |
|
| 556 |
|
| 557 if (data != NULL && data != &PL_sv_undef) |
|
| 558 handler->data = newSVsv(data); |
|
| 559 else |
|
| 560 handler->data = NULL; |
|
| 561 |
|
| 562 cmd_handlers = g_list_append(cmd_handlers, handler); |
|
| 563 |
|
| 564 handler->id = gaim_cmd_register(command, args, priority, flag, prpl_id, |
|
| 565 GAIM_CMD_FUNC(perl_cmd_cb), helpstr, |
|
| 566 handler); |
|
| 567 |
|
| 568 return handler->id; |
|
| 569 } |
|
| 570 |
|
| 571 static void |
|
| 572 destroy_cmd_handler(GaimPerlCmdHandler *handler) |
|
| 573 { |
|
| 574 cmd_handlers = g_list_remove(cmd_handlers, handler); |
|
| 575 |
|
| 576 if (handler->callback != NULL) |
|
| 577 SvREFCNT_dec(handler->callback); |
|
| 578 |
|
| 579 if (handler->data != NULL) |
|
| 580 SvREFCNT_dec(handler->data); |
|
| 581 |
|
| 582 g_free(handler->cmd); |
|
| 583 g_free(handler->prpl_id); |
|
| 584 g_free(handler); |
|
| 585 } |
|
| 586 |
|
| 587 void |
|
| 588 gaim_perl_cmd_clear_for_plugin(GaimPlugin *plugin) |
|
| 589 { |
|
| 590 GList *l, *l_next; |
|
| 591 |
|
| 592 for (l = cmd_handlers; l != NULL; l = l_next) { |
|
| 593 GaimPerlCmdHandler *handler = (GaimPerlCmdHandler *)l->data; |
|
| 594 |
|
| 595 l_next = l->next; |
|
| 596 |
|
| 597 if (handler->plugin == plugin) |
|
| 598 destroy_cmd_handler(handler); |
|
| 599 } |
|
| 600 } |
|
| 601 |
|
| 602 static GaimPerlCmdHandler * |
|
| 603 find_cmd_handler(GaimCmdId id) |
|
| 604 { |
|
| 605 GList *l; |
|
| 606 |
|
| 607 for (l = cmd_handlers; l != NULL; l = l->next) { |
|
| 608 GaimPerlCmdHandler *handler = (GaimPerlCmdHandler *)l->data; |
|
| 609 |
|
| 610 if (handler->id == id) |
|
| 611 return handler; |
|
| 612 } |
|
| 613 |
|
| 614 return NULL; |
|
| 615 } |
|
| 616 |
|
| 617 void |
|
| 618 gaim_perl_cmd_unregister(GaimCmdId id) |
|
| 619 { |
|
| 620 GaimPerlCmdHandler *handler; |
|
| 621 |
|
| 622 handler = find_cmd_handler(id); |
|
| 623 |
|
| 624 if (handler == NULL) { |
|
| 625 croak("Invalid command id in removing a perl command handler.\n"); |
|
| 626 return; |
|
| 627 } |
|
| 628 |
|
| 629 gaim_cmd_unregister(id); |
|
| 630 destroy_cmd_handler(handler); |
|
| 631 } |
|