Mercurial > pidgin.yaz
annotate libgaim/plugins/perl/perl-handlers.c @ 14614:45cdf2cf456c
[gaim-migrate @ 17342]
sf patch #1563203, from hjheins
Add Seamonkey to the list of browsers.
This is the first patch I've accepted in a while. Mostly because Richard has
been doing such an awesome job with the patch tracker. Three cheers for
rlaager! hip-hip, hooray! hip-hip, hooray! hip-hip, hooray!
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sun, 24 Sep 2006 08:11:28 +0000 |
parents | 338ac096e322 |
children | b1fcd2fc903a |
rev | line source |
---|---|
14192 | 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_prepend(l, act); | |
97 } | |
98 | |
99 PUTBACK; | |
100 FREETMPS; | |
101 LEAVE; | |
102 | |
103 return l; | |
104 } | |
105 | |
14364
338ac096e322
[gaim-migrate @ 17070]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14192
diff
changeset
|
106 #ifdef GAIM_GTKPERL |
14192 | 107 GtkWidget * |
108 gaim_perl_gtk_get_plugin_frame(GaimPlugin *plugin) | |
109 { | |
110 SV * sv; | |
111 int count; | |
112 MAGIC *mg; | |
113 GtkWidget *ret; | |
114 GaimPerlScript *gps; | |
115 dSP; | |
116 | |
117 gps = (GaimPerlScript *)plugin->info->extra_info; | |
118 | |
119 ENTER; | |
120 SAVETMPS; | |
121 | |
122 count = call_pv(gps->gtk_prefs_sub, G_SCALAR | G_NOARGS); | |
123 if (count != 1) | |
124 croak("call_pv: Did not return the correct number of values.\n"); | |
125 | |
126 /* the frame was created in a perl sub and is returned */ | |
127 SPAGAIN; | |
128 | |
129 /* We have a Gtk2::Frame on top of the stack */ | |
130 sv = POPs; | |
131 | |
132 /* The magic field hides the pointer to the actual GtkWidget */ | |
133 mg = mg_find(SvRV(sv), PERL_MAGIC_ext); | |
134 ret = (GtkWidget *)mg->mg_ptr; | |
135 | |
136 PUTBACK; | |
137 FREETMPS; | |
138 LEAVE; | |
139 | |
140 return ret; | |
141 } | |
14364
338ac096e322
[gaim-migrate @ 17070]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14192
diff
changeset
|
142 #endif |
14192 | 143 |
144 GaimPluginPrefFrame * | |
145 gaim_perl_get_plugin_frame(GaimPlugin *plugin) | |
146 { | |
147 /* Sets up the Perl Stack for our call back into the script to run the | |
148 * plugin_pref... sub */ | |
149 int count; | |
150 GaimPerlScript *gps; | |
151 GaimPluginPrefFrame *ret_frame; | |
152 dSP; | |
153 | |
154 gps = (GaimPerlScript *)plugin->info->extra_info; | |
155 | |
156 ENTER; | |
157 SAVETMPS; | |
158 /* Some perl magic to run perl_plugin_pref_frame_SV perl sub and | |
159 * return the frame */ | |
160 PUSHMARK(SP); | |
161 PUTBACK; | |
162 | |
163 count = call_pv(gps->prefs_sub, G_SCALAR | G_NOARGS); | |
164 | |
165 SPAGAIN; | |
166 | |
167 if (count != 1) | |
168 croak("call_pv: Did not return the correct number of values.\n"); | |
169 /* the frame was created in a perl sub and is returned */ | |
170 ret_frame = (GaimPluginPrefFrame *)gaim_perl_ref_object(POPs); | |
171 | |
172 /* Tidy up the Perl stack */ | |
173 PUTBACK; | |
174 FREETMPS; | |
175 LEAVE; | |
176 | |
177 return ret_frame; | |
178 } | |
179 | |
180 static void | |
181 destroy_timeout_handler(GaimPerlTimeoutHandler *handler) | |
182 { | |
183 timeout_handlers = g_list_remove(timeout_handlers, handler); | |
184 | |
185 if (handler->callback != NULL) | |
186 SvREFCNT_dec(handler->callback); | |
187 | |
188 if (handler->data != NULL) | |
189 SvREFCNT_dec(handler->data); | |
190 | |
191 g_free(handler); | |
192 } | |
193 | |
194 static void | |
195 destroy_signal_handler(GaimPerlSignalHandler *handler) | |
196 { | |
197 signal_handlers = g_list_remove(signal_handlers, handler); | |
198 | |
199 if (handler->callback != NULL) | |
200 SvREFCNT_dec(handler->callback); | |
201 | |
202 if (handler->data != NULL) | |
203 SvREFCNT_dec(handler->data); | |
204 | |
205 g_free(handler->signal); | |
206 g_free(handler); | |
207 } | |
208 | |
209 static int | |
210 perl_timeout_cb(gpointer data) | |
211 { | |
212 GaimPerlTimeoutHandler *handler = (GaimPerlTimeoutHandler *)data; | |
213 | |
214 dSP; | |
215 ENTER; | |
216 SAVETMPS; | |
217 PUSHMARK(sp); | |
218 XPUSHs((SV *)handler->data); | |
219 PUTBACK; | |
220 call_sv(handler->callback, G_EVAL | G_SCALAR); | |
221 SPAGAIN; | |
222 | |
223 PUTBACK; | |
224 FREETMPS; | |
225 LEAVE; | |
226 | |
227 destroy_timeout_handler(handler); | |
228 | |
229 return 0; | |
230 } | |
231 | |
232 typedef void *DATATYPE; | |
233 | |
234 static void * | |
235 perl_signal_cb(va_list args, void *data) | |
236 { | |
237 GaimPerlSignalHandler *handler = (GaimPerlSignalHandler *)data; | |
238 void *ret_val = NULL; | |
239 int i; | |
240 int count; | |
241 int value_count; | |
242 GaimValue *ret_value, **values; | |
243 SV **sv_args; | |
244 DATATYPE **copy_args; | |
245 STRLEN na; | |
246 | |
247 dSP; | |
248 ENTER; | |
249 SAVETMPS; | |
250 PUSHMARK(sp); | |
251 | |
252 gaim_signal_get_values(handler->instance, handler->signal, | |
253 &ret_value, &value_count, &values); | |
254 | |
255 sv_args = g_new(SV *, value_count); | |
256 copy_args = g_new(void **, value_count); | |
257 | |
258 for (i = 0; i < value_count; i++) { | |
259 sv_args[i] = gaim_perl_sv_from_vargs(values[i], | |
260 (va_list*)&args, | |
261 ©_args[i]); | |
262 | |
263 XPUSHs(sv_args[i]); | |
264 } | |
265 | |
266 XPUSHs((SV *)handler->data); | |
267 | |
268 PUTBACK; | |
269 | |
270 if (ret_value != NULL) { | |
271 count = call_sv(handler->callback, G_EVAL | G_SCALAR); | |
272 | |
273 SPAGAIN; | |
274 | |
275 if (count != 1) | |
276 croak("Uh oh! call_sv returned %i != 1", i); | |
277 else | |
278 ret_val = gaim_perl_data_from_sv(ret_value, POPs); | |
279 } else { | |
280 call_sv(handler->callback, G_SCALAR); | |
281 | |
282 SPAGAIN; | |
283 } | |
284 | |
285 if (SvTRUE(ERRSV)) { | |
286 gaim_debug_error("perl", | |
287 "Perl function exited abnormally: %s\n", | |
288 SvPV(ERRSV, na)); | |
289 } | |
290 | |
291 /* See if any parameters changed. */ | |
292 for (i = 0; i < value_count; i++) { | |
293 if (gaim_value_is_outgoing(values[i])) { | |
294 switch (gaim_value_get_type(values[i])) { | |
295 case GAIM_TYPE_BOOLEAN: | |
296 *((gboolean *)copy_args[i]) = SvIV(sv_args[i]); | |
297 break; | |
298 | |
299 case GAIM_TYPE_INT: | |
300 *((int *)copy_args[i]) = SvIV(sv_args[i]); | |
301 break; | |
302 | |
303 case GAIM_TYPE_UINT: | |
304 *((unsigned int *)copy_args[i]) = SvUV(sv_args[i]); | |
305 break; | |
306 | |
307 case GAIM_TYPE_LONG: | |
308 *((long *)copy_args[i]) = SvIV(sv_args[i]); | |
309 break; | |
310 | |
311 case GAIM_TYPE_ULONG: | |
312 *((unsigned long *)copy_args[i]) = SvUV(sv_args[i]); | |
313 break; | |
314 | |
315 case GAIM_TYPE_INT64: | |
316 *((gint64 *)copy_args[i]) = SvIV(sv_args[i]); | |
317 break; | |
318 | |
319 case GAIM_TYPE_UINT64: | |
320 *((guint64 *)copy_args[i]) = SvUV(sv_args[i]); | |
321 break; | |
322 | |
323 case GAIM_TYPE_STRING: | |
324 if (strcmp(*((char **)copy_args[i]), SvPVX(sv_args[i]))) { | |
325 g_free(*((char **)copy_args[i])); | |
326 *((char **)copy_args[i]) = | |
327 g_strdup(SvPV(sv_args[i], na)); | |
328 } | |
329 break; | |
330 | |
331 case GAIM_TYPE_POINTER: | |
332 *((void **)copy_args[i]) = (void *)SvIV(sv_args[i]); | |
333 break; | |
334 | |
335 case GAIM_TYPE_BOXED: | |
336 *((void **)copy_args[i]) = (void *)SvIV(sv_args[i]); | |
337 break; | |
338 | |
339 default: | |
340 break; | |
341 } | |
342 | |
343 #if 0 | |
344 *((void **)copy_args[i]) = gaim_perl_data_from_sv(values[i], | |
345 sv_args[i]); | |
346 #endif | |
347 } | |
348 } | |
349 | |
350 PUTBACK; | |
351 FREETMPS; | |
352 LEAVE; | |
353 | |
354 g_free(sv_args); | |
355 g_free(copy_args); | |
356 | |
357 gaim_debug_misc("perl", "ret_val = %p\n", ret_val); | |
358 | |
359 return ret_val; | |
360 } | |
361 | |
362 static GaimPerlSignalHandler * | |
363 find_signal_handler(GaimPlugin *plugin, void *instance, const char *signal) | |
364 { | |
365 GaimPerlSignalHandler *handler; | |
366 GList *l; | |
367 | |
368 for (l = signal_handlers; l != NULL; l = l->next) { | |
369 handler = (GaimPerlSignalHandler *)l->data; | |
370 | |
371 if (handler->plugin == plugin && | |
372 handler->instance == instance && | |
373 !strcmp(handler->signal, signal)) { | |
374 return handler; | |
375 } | |
376 } | |
377 | |
378 return NULL; | |
379 } | |
380 | |
381 void | |
382 gaim_perl_timeout_add(GaimPlugin *plugin, int seconds, SV *callback, SV *data) | |
383 { | |
384 GaimPerlTimeoutHandler *handler; | |
385 | |
386 if (plugin == NULL) { | |
387 croak("Invalid handle in adding perl timeout handler.\n"); | |
388 return; | |
389 } | |
390 | |
391 handler = g_new0(GaimPerlTimeoutHandler, 1); | |
392 | |
393 handler->plugin = plugin; | |
394 handler->callback = (callback != NULL && callback != &PL_sv_undef | |
395 ? newSVsv(callback) : NULL); | |
396 handler->data = (data != NULL && data != &PL_sv_undef | |
397 ? newSVsv(data) : NULL); | |
398 | |
399 timeout_handlers = g_list_append(timeout_handlers, handler); | |
400 | |
401 handler->iotag = g_timeout_add(seconds * 1000, perl_timeout_cb, handler); | |
402 } | |
403 | |
404 void | |
405 gaim_perl_timeout_clear_for_plugin(GaimPlugin *plugin) | |
406 { | |
407 GaimPerlTimeoutHandler *handler; | |
408 GList *l, *l_next; | |
409 | |
410 for (l = timeout_handlers; l != NULL; l = l_next) { | |
411 l_next = l->next; | |
412 | |
413 handler = (GaimPerlTimeoutHandler *)l->data; | |
414 | |
415 if (handler->plugin == plugin) | |
416 destroy_timeout_handler(handler); | |
417 } | |
418 } | |
419 | |
420 void | |
421 gaim_perl_timeout_clear(void) | |
422 { | |
423 while (timeout_handlers != NULL) | |
424 destroy_timeout_handler(timeout_handlers->data); | |
425 } | |
426 | |
427 void | |
428 gaim_perl_signal_connect(GaimPlugin *plugin, void *instance, | |
429 const char *signal, SV *callback, SV *data, | |
430 int priority) | |
431 { | |
432 GaimPerlSignalHandler *handler; | |
433 | |
434 handler = g_new0(GaimPerlSignalHandler, 1); | |
435 handler->plugin = plugin; | |
436 handler->instance = instance; | |
437 handler->signal = g_strdup(signal); | |
438 handler->callback = (callback != NULL && | |
439 callback != &PL_sv_undef ? newSVsv(callback) | |
440 : NULL); | |
441 handler->data = (data != NULL && | |
442 data != &PL_sv_undef ? newSVsv(data) : NULL); | |
443 | |
444 signal_handlers = g_list_append(signal_handlers, handler); | |
445 | |
446 gaim_signal_connect_priority_vargs(instance, signal, plugin, | |
447 GAIM_CALLBACK(perl_signal_cb), | |
448 handler, priority); | |
449 } | |
450 | |
451 void | |
452 gaim_perl_signal_disconnect(GaimPlugin *plugin, void *instance, | |
453 const char *signal) | |
454 { | |
455 GaimPerlSignalHandler *handler; | |
456 | |
457 handler = find_signal_handler(plugin, instance, signal); | |
458 | |
459 if (handler == NULL) { | |
460 croak("Invalid signal handler information in " | |
461 "disconnecting a perl signal handler.\n"); | |
462 return; | |
463 } | |
464 | |
465 destroy_signal_handler(handler); | |
466 } | |
467 | |
468 void | |
469 gaim_perl_signal_clear_for_plugin(GaimPlugin *plugin) | |
470 { | |
471 GaimPerlSignalHandler *handler; | |
472 GList *l, *l_next; | |
473 | |
474 for (l = signal_handlers; l != NULL; l = l_next) { | |
475 l_next = l->next; | |
476 | |
477 handler = (GaimPerlSignalHandler *)l->data; | |
478 | |
479 if (handler->plugin == plugin) | |
480 destroy_signal_handler(handler); | |
481 } | |
482 } | |
483 | |
484 void | |
485 gaim_perl_signal_clear(void) | |
486 { | |
487 while (signal_handlers != NULL) | |
488 destroy_signal_handler(signal_handlers->data); | |
489 } | |
490 | |
491 static GaimCmdRet | |
492 perl_cmd_cb(GaimConversation *conv, const gchar *command, | |
493 gchar **args, gchar **error, void *data) | |
494 { | |
495 int i = 0, count, ret_value = GAIM_CMD_RET_OK; | |
496 SV *cmdSV, *tmpSV, *convSV; | |
497 GaimPerlCmdHandler *handler = (GaimPerlCmdHandler *)data; | |
498 | |
499 dSP; | |
500 ENTER; | |
501 SAVETMPS; | |
502 PUSHMARK(SP); | |
503 | |
504 /* Push the conversation onto the perl stack */ | |
505 convSV = sv_2mortal(gaim_perl_bless_object(conv, "Gaim::Conversation")); | |
506 XPUSHs(convSV); | |
507 | |
508 /* Push the command string onto the perl stack */ | |
509 cmdSV = newSVpv(command, 0); | |
510 cmdSV = sv_2mortal(cmdSV); | |
511 XPUSHs(cmdSV); | |
512 | |
513 /* Push the data onto the perl stack */ | |
514 XPUSHs((SV *)handler->data); | |
515 | |
516 /* Push any arguments we may have */ | |
517 for (i = 0; args[i] != NULL; i++) { | |
518 /* XXX The mortality of these created SV's should prevent | |
519 * memory issues, if I read/understood everything correctly... | |
520 */ | |
521 tmpSV = newSVpv(args[i], 0); | |
522 tmpSV = sv_2mortal(tmpSV); | |
523 XPUSHs(tmpSV); | |
524 } | |
525 | |
526 PUTBACK; | |
527 count = call_sv(handler->callback, G_EVAL|G_SCALAR); | |
528 | |
529 if (count != 1) | |
530 croak("call_sv: Did not return the correct number of values.\n"); | |
531 | |
532 SPAGAIN; | |
533 | |
534 ret_value = POPi; | |
535 | |
536 PUTBACK; | |
537 FREETMPS; | |
538 LEAVE; | |
539 | |
540 return ret_value; | |
541 } | |
542 | |
543 GaimCmdId | |
544 gaim_perl_cmd_register(GaimPlugin *plugin, const gchar *command, | |
545 const gchar *args, GaimCmdPriority priority, | |
546 GaimCmdFlag flag, const gchar *prpl_id, SV *callback, | |
547 const gchar *helpstr, SV *data) | |
548 { | |
549 GaimPerlCmdHandler *handler; | |
550 | |
551 handler = g_new0(GaimPerlCmdHandler, 1); | |
552 handler->plugin = plugin; | |
553 handler->cmd = g_strdup(command); | |
554 handler->prpl_id = g_strdup(prpl_id); | |
555 | |
556 if (callback != NULL && callback != &PL_sv_undef) | |
557 handler->callback = newSVsv(callback); | |
558 else | |
559 handler->callback = NULL; | |
560 | |
561 if (data != NULL && data != &PL_sv_undef) | |
562 handler->data = newSVsv(data); | |
563 else | |
564 handler->data = NULL; | |
565 | |
566 cmd_handlers = g_list_append(cmd_handlers, handler); | |
567 | |
568 handler->id = gaim_cmd_register(command, args, priority, flag, prpl_id, | |
569 GAIM_CMD_FUNC(perl_cmd_cb), helpstr, | |
570 handler); | |
571 | |
572 return handler->id; | |
573 } | |
574 | |
575 static void | |
576 destroy_cmd_handler(GaimPerlCmdHandler *handler) | |
577 { | |
578 cmd_handlers = g_list_remove(cmd_handlers, handler); | |
579 | |
580 if (handler->callback != NULL) | |
581 SvREFCNT_dec(handler->callback); | |
582 | |
583 if (handler->data != NULL) | |
584 SvREFCNT_dec(handler->data); | |
585 | |
586 g_free(handler->cmd); | |
587 g_free(handler->prpl_id); | |
588 g_free(handler); | |
589 } | |
590 | |
591 void | |
592 gaim_perl_cmd_clear_for_plugin(GaimPlugin *plugin) | |
593 { | |
594 GList *l, *l_next; | |
595 | |
596 for (l = cmd_handlers; l != NULL; l = l_next) { | |
597 GaimPerlCmdHandler *handler = (GaimPerlCmdHandler *)l->data; | |
598 | |
599 l_next = l->next; | |
600 | |
601 if (handler->plugin == plugin) | |
602 destroy_cmd_handler(handler); | |
603 } | |
604 } | |
605 | |
606 static GaimPerlCmdHandler * | |
607 find_cmd_handler(GaimCmdId id) | |
608 { | |
609 GList *l; | |
610 | |
611 for (l = cmd_handlers; l != NULL; l = l->next) { | |
612 GaimPerlCmdHandler *handler = (GaimPerlCmdHandler *)l->data; | |
613 | |
614 if (handler->id == id) | |
615 return handler; | |
616 } | |
617 | |
618 return NULL; | |
619 } | |
620 | |
621 void | |
622 gaim_perl_cmd_unregister(GaimCmdId id) | |
623 { | |
624 GaimPerlCmdHandler *handler; | |
625 | |
626 handler = find_cmd_handler(id); | |
627 | |
628 if (handler == NULL) { | |
629 croak("Invalid command id in removing a perl command handler.\n"); | |
630 return; | |
631 } | |
632 | |
633 gaim_cmd_unregister(id); | |
634 destroy_cmd_handler(handler); | |
635 } |