comparison src/module.c @ 2393:a7ecfd3f7714

[gaim-migrate @ 2406] Arkadiusz Miskiewicz\'s Gadu-Gadu plugin. I was able to figure out enough polish to be able to download Gadu-Gadu, create an account, and test the plugin. Imagine my shock when I got my info and it said I was a woman. Whoops. Also splitting plugins.c so that non-gtk stuff is in modules.c. gaim-core is almost ready for protocol implantaion. Also fixing an IRC bug. Also patiently waiting for anoncvs_gaim's lock in /cvsroot/gaim/gaim/pixmaps committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sat, 29 Sep 2001 23:06:30 +0000
parents
children 6e637ad18494
comparison
equal deleted inserted replaced
2392:9965c0bbdb7c 2393:a7ecfd3f7714
1 /*
2 * gaim
3 *
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * ----------------
21 * The Plug-in plug
22 *
23 * Plugin support is currently being maintained by Mike Saraf
24 * msaraf@dwc.edu
25 *
26 * Well, I didn't see any work done on it for a while, so I'm going to try
27 * my hand at it. - Eric warmenhoven@yahoo.com
28 *
29 * Mike is my roomate. I can assure you that he's lazy :-P -- Rob rob@marko.net
30 *
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #ifdef GAIM_PLUGINS
38
39 #include <string.h>
40 #include <sys/time.h>
41
42 #include <sys/types.h>
43 #include <sys/stat.h>
44
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include "gaim.h"
49
50 /* ------------------ Global Variables ----------------------- */
51
52 GList *plugins = NULL;
53 GList *callbacks = NULL;
54
55 /* --------------- Function Declarations --------------------- */
56
57 struct gaim_plugin * load_plugin(char *);
58 void unload_plugin(struct gaim_plugin *p);
59 struct gaim_plugin *reload_plugin(struct gaim_plugin *p);
60
61 void gaim_signal_connect(GModule *, enum gaim_event, void *, void *);
62 void gaim_signal_disconnect(GModule *, enum gaim_event, void *);
63 void gaim_plugin_unload(GModule *);
64
65 /* --------------- Static Function Declarations ------------- */
66
67 static void plugin_remove_callbacks(GModule *);
68
69 /* ------------------ Code Below ---------------------------- */
70
71 struct gaim_plugin *load_plugin(char *filename)
72 {
73 struct gaim_plugin *plug;
74 GList *c = plugins;
75 char *(*gaim_plugin_init)(GModule *);
76 char *(*cfunc)();
77 char *error;
78 char *retval;
79
80 if (!g_module_supported())
81 return NULL;
82 if (filename && !strlen(filename))
83 return NULL;
84
85 while (filename && c) {
86 plug = (struct gaim_plugin *)c->data;
87 if (!strcmp(filename, g_module_name(plug->handle))) {
88 /* just need to reload plugin */
89 return reload_plugin(plug);
90 } else
91 c = g_list_next(c);
92 }
93 plug = g_malloc(sizeof *plug);
94
95 debug_printf("Loading %s\n", filename);
96 plug->handle = g_module_open(filename, 0);
97 if (!plug->handle) {
98 error = (char *)g_module_error();
99 do_error_dialog(error, _("Plugin Error"));
100 g_free(plug);
101 return NULL;
102 }
103
104 if (!g_module_symbol(plug->handle, "gaim_plugin_init", (gpointer *)&gaim_plugin_init)) {
105 do_error_dialog(g_module_error(), _("Plugin Error"));
106 g_module_close(plug->handle);
107 g_free(plug);
108 return NULL;
109 }
110
111 retval = (*gaim_plugin_init)(plug->handle);
112 debug_printf("loaded plugin returned %s\n", retval ? retval : "NULL");
113 if (retval) {
114 plugin_remove_callbacks(plug->handle);
115 do_error_dialog(retval, _("Plugin Error"));
116 g_module_close(plug->handle);
117 g_free(plug);
118 return NULL;
119 }
120
121 plugins = g_list_append(plugins, plug);
122
123 if (g_module_symbol(plug->handle, "name", (gpointer *)&cfunc)) {
124 plug->name = (*cfunc)();
125 } else {
126 plug->name = NULL;
127 }
128
129 if (g_module_symbol(plug->handle, "description", (gpointer *)&cfunc))
130 plug->description = (*cfunc)();
131 else
132 plug->description = NULL;
133
134 save_prefs();
135 return plug;
136 }
137
138 static void unload_gaim_plugin(struct gaim_plugin *p)
139 {
140 void (*gaim_plugin_remove)();
141
142 debug_printf("Unloading %s\n", g_module_name(p->handle));
143
144 /* Attempt to call the plugin's remove function (if there) */
145 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
146 (*gaim_plugin_remove)();
147
148 plugin_remove_callbacks(p->handle);
149
150 plugins = g_list_remove(plugins, p);
151 g_free(p);
152 save_prefs();
153 }
154
155 void unload_plugin(struct gaim_plugin *p)
156 {
157 GModule *handle = p->handle;
158 unload_gaim_plugin(p);
159 g_module_close(handle);
160 }
161
162 static gboolean unload_timeout(gpointer handle)
163 {
164 g_module_close(handle);
165 return FALSE;
166 }
167
168 void gaim_plugin_unload(GModule *handle)
169 {
170 g_timeout_add(5000, unload_timeout, handle);
171 }
172
173 /* Do unload/load cycle of plugin. */
174 struct gaim_plugin *reload_plugin(struct gaim_plugin *p)
175 {
176 char file[1024];
177 GModule *handle = p->handle;
178
179 strncpy(file, g_module_name(handle), sizeof(file));
180 file[sizeof(file) - 1] = '\0';
181
182 debug_printf("Reloading %s\n", file);
183
184 /* Unload */
185 unload_plugin(p);
186
187 /* Load */
188 return load_plugin(file);
189 }
190
191 /* Remove all callbacks associated with plugin handle */
192 static void plugin_remove_callbacks(GModule *handle)
193 {
194 GList *c = callbacks;
195 struct gaim_callback *g;
196
197 debug_printf("%d callbacks to search\n", g_list_length(callbacks));
198
199 while (c) {
200 g = (struct gaim_callback *)c->data;
201 if (g->handle == handle) {
202 c = g_list_next(c);
203 callbacks = g_list_remove(callbacks, (gpointer)g);
204 debug_printf("Removing callback, %d remain\n", g_list_length(callbacks));
205 } else
206 c = g_list_next(c);
207 }
208 }
209
210 void gaim_signal_connect(GModule *handle, enum gaim_event which, void *func, void *data)
211 {
212 struct gaim_callback *call = g_new0(struct gaim_callback, 1);
213 call->handle = handle;
214 call->event = which;
215 call->function = func;
216 call->data = data;
217
218 callbacks = g_list_append(callbacks, call);
219 debug_printf("Adding callback %d\n", g_list_length(callbacks));
220 }
221
222 void gaim_signal_disconnect(GModule *handle, enum gaim_event which, void *func)
223 {
224 GList *c = callbacks;
225 struct gaim_callback *g = NULL;
226
227 while (c) {
228 g = (struct gaim_callback *)c->data;
229 if (handle == g->handle && func == g->function) {
230 callbacks = g_list_remove(callbacks, c->data);
231 g_free(g);
232 c = callbacks;
233 if (c == NULL)
234 break;
235 }
236 c = g_list_next(c);
237 }
238 }
239
240 #endif /* GAIM_PLUGINS */
241
242 static char *event_name(enum gaim_event event)
243 {
244 static char buf[128];
245 switch (event) {
246 case event_signon:
247 sprintf(buf, "event_signon");
248 break;
249 case event_signoff:
250 sprintf(buf, "event_signoff");
251 break;
252 case event_away:
253 sprintf(buf, "event_away");
254 break;
255 case event_back:
256 sprintf(buf, "event_back");
257 break;
258 case event_im_recv:
259 sprintf(buf, "event_im_recv");
260 break;
261 case event_im_send:
262 sprintf(buf, "event_im_send");
263 break;
264 case event_buddy_signon:
265 sprintf(buf, "event_buddy_signon");
266 break;
267 case event_buddy_signoff:
268 sprintf(buf, "event_buddy_signoff");
269 break;
270 case event_buddy_away:
271 sprintf(buf, "event_buddy_away");
272 break;
273 case event_buddy_back:
274 sprintf(buf, "event_buddy_back");
275 break;
276 case event_buddy_idle:
277 sprintf(buf, "event_buddy_idle");
278 break;
279 case event_buddy_unidle:
280 sprintf(buf, "event_buddy_unidle");
281 break;
282 case event_blist_update:
283 sprintf(buf, "event_blist_update");
284 break;
285 case event_chat_invited:
286 sprintf(buf, "event_chat_invited");
287 break;
288 case event_chat_join:
289 sprintf(buf, "event_chat_join");
290 break;
291 case event_chat_leave:
292 sprintf(buf, "event_chat_leave");
293 break;
294 case event_chat_buddy_join:
295 sprintf(buf, "event_chat_buddy_join");
296 break;
297 case event_chat_buddy_leave:
298 sprintf(buf, "event_chat_buddy_leave");
299 break;
300 case event_chat_recv:
301 sprintf(buf, "event_chat_recv");
302 break;
303 case event_chat_send:
304 sprintf(buf, "event_chat_send");
305 break;
306 case event_warned:
307 sprintf(buf, "event_warned");
308 break;
309 case event_error:
310 sprintf(buf, "event_error");
311 break;
312 case event_quit:
313 sprintf(buf, "event_quit");
314 break;
315 case event_new_conversation:
316 sprintf(buf, "event_new_conversation");
317 break;
318 case event_set_info:
319 sprintf(buf, "event_set_info");
320 break;
321 case event_draw_menu:
322 sprintf(buf, "event_draw_menu");
323 break;
324 case event_im_displayed_sent:
325 sprintf(buf, "event_im_displayed_sent");
326 break;
327 case event_im_displayed_rcvd:
328 sprintf(buf, "event_im_displayed_rcvd");
329 break;
330 case event_chat_send_invite:
331 sprintf(buf, "event_chat_send_invite");
332 break;
333 default:
334 sprintf(buf, "event_unknown");
335 break;
336 }
337 return buf;
338 }
339
340 int plugin_event(enum gaim_event event, void *arg1, void *arg2, void *arg3, void *arg4)
341 {
342 #ifdef USE_PERL
343 char buf[BUF_LONG];
344 #endif
345 #ifdef GAIM_PLUGINS
346 GList *c = callbacks;
347 struct gaim_callback *g;
348
349 while (c) {
350 void (*zero)(void *);
351 void (*one)(void *, void *);
352 void (*two)(void *, void *, void *);
353 void (*three)(void *, void *, void *, void *);
354 void (*four)(void *, void *, void *, void *, void *);
355
356 g = (struct gaim_callback *)c->data;
357 if (g->event == event && g->function !=NULL) {
358 switch (event) {
359
360 /* no args */
361 case event_blist_update:
362 case event_quit:
363 zero = g->function;
364 (*zero)(g->data);
365 break;
366
367 /* one arg */
368 case event_signon:
369 case event_signoff:
370 case event_new_conversation:
371 case event_error:
372 one = g->function;
373 (*one)(arg1, g->data);
374 break;
375
376 /* two args */
377 case event_buddy_signon:
378 case event_buddy_signoff:
379 case event_buddy_away:
380 case event_buddy_back:
381 case event_buddy_idle:
382 case event_buddy_unidle:
383 case event_chat_leave:
384 case event_set_info:
385 case event_draw_menu:
386 two = g->function;
387 (*two)(arg1, arg2, g->data);
388 break;
389
390 /* three args */
391 case event_im_send:
392 case event_im_displayed_sent:
393 case event_chat_join:
394 case event_chat_buddy_join:
395 case event_chat_buddy_leave:
396 case event_chat_send:
397 case event_away:
398 case event_back:
399 case event_warned:
400 three = g->function;
401 (*three)(arg1, arg2, arg3, g->data);
402 break;
403
404 /* four args */
405 case event_im_recv:
406 case event_chat_recv:
407 case event_im_displayed_rcvd:
408 case event_chat_send_invite:
409 case event_chat_invited:
410 four = g->function;
411 (*four)(arg1, arg2, arg3, arg4, g->data);
412 break;
413
414 default:
415 debug_printf("unknown event %d\n", event);
416 break;
417 }
418 }
419 c = c->next;
420 }
421 #endif /* GAIM_PLUGINS */
422 #ifdef USE_PERL
423 switch (event) {
424 case event_signon:
425 case event_signoff:
426 case event_away:
427 case event_back:
428 g_snprintf(buf, sizeof buf, "%lu", (unsigned long)arg1);
429 break;
430 case event_im_recv:
431 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
432 *(char **)arg2 ? *(char **)arg2 : "(null)",
433 *(char **)arg3 ? *(char **)arg3 : "(null)");
434 break;
435 case event_im_send:
436 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
437 (char *)arg2, *(char **)arg3 ? *(char **)arg3 : "(null)");
438 break;
439 case event_buddy_signon:
440 case event_buddy_signoff:
441 case event_set_info:
442 case event_buddy_away:
443 case event_buddy_back:
444 case event_buddy_idle:
445 case event_buddy_unidle:
446 g_snprintf(buf, sizeof buf, "%lu \"%s\"", (unsigned long)arg1, (char *)arg2);
447 break;
448 case event_chat_invited:
449 g_snprintf(buf, sizeof buf, "%lu \"%s\" \"%s\" %s", (unsigned long)arg1,
450 (char *)arg2, (char *)arg3, arg4 ? (char *)arg4 : "");
451 break;
452 case event_chat_join:
453 case event_chat_buddy_join:
454 case event_chat_buddy_leave:
455 g_snprintf(buf, sizeof buf, "%lu %d \"%s\"", (unsigned long)arg1,
456 (int)arg2, (char *)arg3);
457 break;
458 case event_chat_leave:
459 g_snprintf(buf, sizeof buf, "%lu %d", (unsigned long)arg1, (int)arg2);
460 break;
461 case event_chat_recv:
462 g_snprintf(buf, sizeof buf, "%lu %d \"%s\" %s", (unsigned long)arg1,
463 (int)arg2, (char *)arg3, (char *)arg4 ? (char *)arg4 : "(null)");
464 break;
465 case event_chat_send_invite:
466 g_snprintf(buf, sizeof buf, "%lu %d \"%s\" %s", (unsigned long)arg1,
467 (int)arg2, (char *)arg3, *(char **)arg4 ? *(char **)arg4 : "(null)");
468 break;
469 case event_chat_send:
470 g_snprintf(buf, sizeof buf, "%lu %d %s", (unsigned long)arg1, (int)arg2,
471 *(char **)arg3 ? *(char **)arg3 : "(null)");
472 break;
473 case event_warned:
474 g_snprintf(buf, sizeof buf, "%lu \"%s\" %d", (unsigned long)arg1,
475 arg2 ? (char *)arg2 : "", (int)arg3);
476 break;
477 case event_quit:
478 buf[0] = 0;
479 break;
480 case event_new_conversation:
481 g_snprintf(buf, sizeof buf, "\"%s\"", (char *)arg1);
482 break;
483 case event_im_displayed_sent:
484 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
485 (char *)arg2, *(char **)arg3 ? *(char **)arg3 : "(null)");
486 break;
487 case event_im_displayed_rcvd:
488 g_snprintf(buf, sizeof buf, "%lu \"%s\" %s", (unsigned long)arg1,
489 (char *)arg2, (char *)arg3 ? (char *)arg3 : "(null)");
490 break;
491 default:
492 return 0;
493 }
494 return perl_event(event_name(event), buf);
495 #else
496 return 0;
497 #endif
498 }
499
500 /* Calls the gaim_plugin_remove function in any loaded plugin that has one */
501 #ifdef GAIM_PLUGINS
502 void remove_all_plugins()
503 {
504 GList *c = plugins;
505 struct gaim_plugin *p;
506 void (*gaim_plugin_remove)();
507
508 while (c) {
509 p = (struct gaim_plugin *)c->data;
510 if (g_module_symbol(p->handle, "gaim_plugin_remove", (gpointer *)&gaim_plugin_remove))
511 (*gaim_plugin_remove)();
512 g_free(p);
513 c = c->next;
514 }
515 }
516 #endif