ruburple 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1239 @@
1
+ // Ruburple - a ruby wrapper for libpurple
2
+ // Copyright (C) 2007 Martin Kihlgren <zond at troja dot ath dot cx>
3
+ //
4
+ // This program is free software; you can redistribute it and/or
5
+ // modify it under the terms of the GNU General Public License
6
+ // as published by the Free Software Foundation; either version 2
7
+ // of the License, or (at your option) any later version.
8
+ //
9
+ // This program is distributed in the hope that it will be useful,
10
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ // GNU General Public License for more details.
13
+ //
14
+ // You should have received a copy of the GNU General Public License
15
+ // along with this program; if not, write to the Free Software
16
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
+
18
+ #include <libpurple/account.h>
19
+ #include <libpurple/conversation.h>
20
+ #include <libpurple/core.h>
21
+ #include <libpurple/debug.h>
22
+ #include <libpurple/cipher.h>
23
+ #include <libpurple/eventloop.h>
24
+ #include <libpurple/ft.h>
25
+ #include <libpurple/log.h>
26
+ #include <libpurple/notify.h>
27
+ #include <libpurple/prefs.h>
28
+ #include <libpurple/prpl.h>
29
+ #include <libpurple/pounce.h>
30
+ #include <libpurple/savedstatuses.h>
31
+ #include <libpurple/sound.h>
32
+ #include <libpurple/status.h>
33
+ #include <libpurple/util.h>
34
+ #include <libpurple/whiteboard.h>
35
+
36
+ #include <glib.h>
37
+ #include <stdio.h>
38
+ #include <string.h>
39
+ #include <unistd.h>
40
+ #include <errno.h>
41
+ #include <ruby.h>
42
+ #include <stdarg.h>
43
+
44
+ /*
45
+ * The ruby classes.
46
+ */
47
+ static VALUE rb_ruburple;
48
+ static VALUE rb_ruburple_plugin;
49
+ static VALUE rb_ruburple_protocol;
50
+ static VALUE rb_ruburple_protocol_info;
51
+ static VALUE rb_ruburple_protocol_account;
52
+ static VALUE rb_ruburple_protocol_account_transfer;
53
+ static VALUE rb_ruburple_protocol_account_conversation;
54
+ static VALUE rb_ruburple_protocol_account_chat;
55
+ static VALUE rb_ruburple_protocol_account_savedstatus;
56
+ static VALUE rb_ruburple_protocol_connection;
57
+ static VALUE rb_ruburple_blist_status;
58
+ static VALUE rb_ruburple_blist;
59
+ static VALUE rb_ruburple_blist_buddy_icon;
60
+ static VALUE rb_ruburple_blist_buddy;
61
+ static VALUE rb_ruburple_blist_node;
62
+ static VALUE rb_ruburple_blist_group;
63
+ static VALUE rb_ruburple_handle;
64
+ static VALUE rb_ruburple_cipher;
65
+ static VALUE rb_ruburple_log;
66
+ static VALUE rb_ruburple_xmlnode;
67
+ static VALUE rb_ruburple_userinfo;
68
+ static VALUE rb_ruburple_storedimage;
69
+ static VALUE rb_ruburple_subscription;
70
+ static VALUE rb_ruburple_pointer;
71
+
72
+ /*
73
+ * A few globals.
74
+ */
75
+ static GMainLoop *main_loop;
76
+ static VALUE call_method_id;
77
+ static VALUE idle_handler_method_id;
78
+ static int purple_event_queue[2];
79
+
80
+ /*
81
+ * The UI name for libpurple.
82
+ */
83
+ #define UI_ID "ruburple"
84
+
85
+ /**
86
+ * The following eventloop functions are used in both pidgin and purple-text. If your
87
+ * application uses glib mainloop, you can safely use this verbatim.
88
+ */
89
+ #define PURPLE_GLIB_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
90
+ #define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
91
+
92
+ /* util macros */
93
+ #define FATAL(s, ...) fprintf(stderr, "FATAL: "); fprintf(stderr, s, ## __VA_ARGS__); fprintf(stderr, "\n"); exit(1)
94
+ #define RETURN_QNIL_IF_NULL(pointer) if (pointer == NULL) return Qnil
95
+
96
+ /*
97
+ * Conversions from c to ruby.
98
+ */
99
+ #define BOOL(gbool) (gbool == FALSE ? Qfalse : Qtrue)
100
+ #define RB_RUBURPLE_PROTOCOL_ACCOUNT(purple_account_pointer) Data_Wrap_Struct(rb_ruburple_protocol_account, NULL, NULL, purple_account_pointer)
101
+ #define RB_RUBURPLE_PROTOCOL_ACCOUNT_gc(purple_account_pointer) Data_Wrap_Struct(rb_ruburple_protocol_account, NULL, rb_ruburple_protocol_account_free, purple_account_pointer)
102
+ #define RB_RUBURPLE_PROTOCOL_ACCOUNT_CONVERSATION(purple_conversation_pointer) Data_Wrap_Struct(rb_ruburple_protocol_account_conversation, NULL, NULL, purple_conversation_pointer)
103
+ #define RB_RUBURPLE_PROTOCOL_ACCOUNT_TRANSFER(purple_xfer_pointer) Data_Wrap_Struct(rb_ruburple_protocol_account_transfer, NULL, NULL, purple_xfer_pointer)
104
+ #define RB_RUBURPLE_PROTOCOL_ACCOUNT_CHAT(purple_chat_pointer) Data_Wrap_Struct(rb_ruburple_protocol_account_chat, NULL, NULL, purple_chat_pointer)
105
+ #define RB_RUBURPLE_PROTOCOL_CONNECTION(purple_connection_pointer) Data_Wrap_Struct(rb_ruburple_protocol_connection, NULL, NULL, purple_connection_pointer)
106
+ #define RB_RUBURPLE_PROTOCOL_ACCOUNT_SAVEDSTATUS(purple_savedstatus_pointer) Data_Wrap_Struct(rb_ruburple_protocol_account_savedstatus, NULL, NULL, purple_savedstatus_pointer)
107
+ #define RB_RUBURPLE_PROTOCOL(purple_plugin_pointer) Data_Wrap_Struct(rb_ruburple_protocol, NULL, NULL, purple_plugin_pointer)
108
+ #define RB_RUBURPLE_PLUGIN(purple_plugin_pointer) Data_Wrap_Struct(rb_ruburple_plugin, NULL, NULL, purple_plugin_pointer)
109
+ #define RB_RUBURPLE_PROTOCOL_INFO(purple_plugin_info_pointer) Data_Wrap_Struct(rb_ruburple_protocol_info, NULL, NULL, purple_plugin_info_pointer)
110
+ #define RB_RUBURPLE_BLIST_STATUS(purple_status_pointer) Data_Wrap_Struct(rb_ruburple_blist_status, NULL, NULL, purple_status_pointer)
111
+ #define RB_RUBURPLE_BLIST(purple_blist_pointer) Data_Wrap_Struct(rb_ruburple_blist, NULL, NULL, purple_blist_pointer)
112
+ #define RB_RUBURPLE_BLIST_BUDDY(purple_buddy_pointer) Data_Wrap_Struct(rb_ruburple_blist_buddy, NULL, NULL, purple_buddy_pointer)
113
+ #define RB_RUBURPLE_BLIST_NODE(purple_blist_node_pointer) Data_Wrap_Struct(rb_ruburple_blist_node, NULL, NULL, purple_blist_node_pointer)
114
+ #define RB_RUBURPLE_BLIST_GROUP(purple_blist_group_pointer) Data_Wrap_Struct(rb_ruburple_blist_group, NULL, NULL, purple_blist_group_pointer)
115
+ #define RB_RUBURPLE_BLIST_BUDDY_ICON(purple_buddy_icon_pointer) Data_Wrap_Struct(rb_ruburple_blist_buddy_icon, NULL, NULL, purple_buddy_icon_pointer)
116
+ #define RB_RUBURPLE_HANDLE(void_pointer) Data_Wrap_Struct(rb_ruburple_handle, NULL, NULL, void_pointer)
117
+ #define RB_RUBURPLE_CIPHER(purple_cipher_pointer) Data_Wrap_Struct(rb_ruburple_cipher, NULL, NULL, purple_cipher_pointer)
118
+ #define RB_RUBURPLE_LOG(purple_log_pointer) Data_Wrap_Struct(rb_ruburple_log, NULL, NULL, purple_log_pointer)
119
+ #define RB_RUBURPLE_XMLNODE(xmlnode_pointer) Data_Wrap_Struct(rb_ruburple_xmlnode, NULL, NULL, xmlnode_pointer)
120
+ #define RB_RUBURPLE_USERINFO(purple_notify_user_info_pointer) Data_Wrap_Struct(rb_ruburple_userinfo, NULL, NULL, purple_notify_user_info_pointer)
121
+ #define RB_RUBURPLE_STOREDIMAGE(purple_stored_image_pointer) Data_Wrap_Struct(rb_ruburple_storedimage, NULL, NULL, purple_stored_image_pointer)
122
+ #define RB_RUBURPLE_SUBSCRIPTION_gc(ruburple_signal_handler_pointer) Data_Wrap_Struct(rb_ruburple_subscription, ruburple_signal_handler_mark, ruburple_signal_handler_free, ruburple_signal_handler_pointer)
123
+ #define RB_RUBURPLE_POINTER(gpointer) Data_Wrap_Struct(rb_ruburple_pointer, NULL, NULL, gpointer)
124
+
125
+ /*
126
+ * Conversions from ruby to c.
127
+ */
128
+ #define GBOOL(bool) ((bool == Qnil || bool == Qfalse) ? FALSE : TRUE)
129
+ #define PURPLE_ACCOUNT(rb_ruburple_protocol_account,purple_account_pointer) Data_Get_Struct(rb_ruburple_protocol_account, PurpleAccount, purple_account_pointer)
130
+ #define PURPLE_PLUGIN(rb_ruburple_protocol,purple_plugin_pointer) Data_Get_Struct(rb_ruburple_protocol, PurplePlugin, purple_plugin_pointer)
131
+ #define PURPLE_PLUGIN_INFO(rb_ruburple_protocol_info,purple_plugin_info_pointer) Data_Get_Struct(rb_ruburple_protocol_info, PurplePluginInfo, purple_plugin_info_pointer)
132
+ #define PURPLE_SAVEDSTATUS(rb_ruburple_protocol_account_savedstatus,purple_saved_status_pointer) Data_Get_Struct(rb_ruburple_protocol_account_savedstatus, PurpleSavedStatus, purple_saved_status_pointer)
133
+ #define RUBURPLE_SIGNAL_HANDLER(rb_ruburple_subscription,ruburple_signal_handler_pointer) Data_Get_Struct(rb_ruburple_subscription, RuburpleSignalHandler, ruburple_signal_handler_pointer)
134
+ #define PURPLE_CONNECTION(rb_ruburple_protocol_connection,purple_connection_pointer) Data_Get_Struct(rb_ruburple_protocol_connection, PurpleConnection, purple_connection_pointer)
135
+ #define GPOINTER(rb_ruburple_pointer,gpointer) Data_Get_Struct(rb_ruburple_pointer, void, gpointer)
136
+
137
+ /*
138
+ * The libpurple signal handler for Ruburple.
139
+ */
140
+ typedef struct
141
+ {
142
+ gpointer handle;
143
+ VALUE callable;
144
+ char *signal;
145
+ } RuburpleSignalHandler;
146
+
147
+ static RuburpleSignalHandler*
148
+ ruburple_signal_handler_new(gpointer handle, char *signal_name, VALUE callable)
149
+ {
150
+ RuburpleSignalHandler *handler = g_new(RuburpleSignalHandler, 1);
151
+ handler->handle = handle;
152
+ handler->signal = strdup(signal_name);
153
+ handler->callable = callable;
154
+ return handler;
155
+ }
156
+
157
+ static void
158
+ ruburple_signal_handler_free(RuburpleSignalHandler *handler)
159
+ {
160
+ g_free(handler->signal);
161
+ g_free(handler);
162
+ }
163
+
164
+ static void
165
+ ruburple_signal_handler_mark(RuburpleSignalHandler *handler)
166
+ {
167
+ rb_gc_mark(handler->callable);
168
+ }
169
+
170
+ /*
171
+ * A definition of an incoming event for ruby.
172
+ */
173
+ typedef struct
174
+ {
175
+ VALUE receiver;
176
+ VALUE method;
177
+ int argc;
178
+ VALUE *argv;
179
+ GMutex *lock;
180
+ GCond *flag;
181
+ } IncomingRuburpleEvent;
182
+
183
+ /*
184
+ * Asking the glib main loop to do stuff for us.
185
+ */
186
+
187
+ /* A shorthand for a generic function */
188
+ typedef gpointer (*RuburpleCallFunc)(gpointer);
189
+
190
+ /* A definition of something we want run once */
191
+ typedef struct
192
+ {
193
+ RuburpleCallFunc function;
194
+ gpointer data;
195
+ gpointer result;
196
+ GCond *done;
197
+ GMutex *lock;
198
+ gboolean do_free;
199
+ gboolean run;
200
+ } RuburpleSingleShotCall;
201
+
202
+ /* Creator of single shot calls */
203
+ static RuburpleSingleShotCall*
204
+ ruburple_single_shot_call_new(RuburpleCallFunc function, gpointer data, gboolean do_free)
205
+ {
206
+ RuburpleSingleShotCall *return_value = g_new(RuburpleSingleShotCall, 1);
207
+ return_value->function = function;
208
+ return_value->data = data;
209
+ return_value->do_free = do_free;
210
+ return_value->run = FALSE;
211
+ return_value->done = g_cond_new();
212
+ return_value->lock = g_mutex_new();
213
+ return return_value;
214
+ }
215
+
216
+ /* Destructor of single shot calls */
217
+ static void
218
+ ruburple_single_shot_call_free(RuburpleSingleShotCall *call)
219
+ {
220
+ g_mutex_free(call->lock);
221
+ g_cond_free(call->done);
222
+ g_free(call);
223
+ }
224
+
225
+ /* Call one of our single shots */
226
+ static gboolean
227
+ call_single_shot(gpointer data)
228
+ {
229
+ RuburpleSingleShotCall *call = (RuburpleSingleShotCall *) data;
230
+
231
+ g_mutex_lock(call->lock);
232
+
233
+ call->result = call->function(call->data);
234
+ call->run = TRUE;
235
+ g_cond_broadcast(call->done);
236
+
237
+ g_mutex_unlock(call->lock);
238
+
239
+ if (call->do_free) {
240
+ ruburple_single_shot_call_free(call);
241
+ }
242
+
243
+ return FALSE;
244
+ }
245
+
246
+ /* Ask glib to run something once */
247
+ static RuburpleSingleShotCall*
248
+ add_single_shot(RuburpleCallFunc function, gpointer data, gboolean do_free)
249
+ {
250
+ RuburpleSingleShotCall *call = ruburple_single_shot_call_new(function, data, do_free);
251
+ g_idle_add(call_single_shot, call);
252
+ return call;
253
+ }
254
+
255
+ /* Ask glib to run something for us once and wait for the result to be ready */
256
+ static gpointer
257
+ call_and_get_result(RuburpleCallFunc function, gpointer data)
258
+ {
259
+ RuburpleSingleShotCall *call = add_single_shot(function, data, FALSE);
260
+ gpointer return_value;
261
+
262
+ g_mutex_lock(call->lock);
263
+
264
+ while (!call->run) {
265
+ g_cond_wait(call->done, call->lock);
266
+ }
267
+
268
+ return_value = call->result;
269
+
270
+ g_mutex_unlock(call->lock);
271
+
272
+ ruburple_single_shot_call_free(call);
273
+
274
+ return return_value;
275
+ }
276
+
277
+ /*
278
+ * The magical stuff taken more or less verbatim from nullclient.c
279
+ */
280
+
281
+ typedef struct _PurpleGLibIOClosure {
282
+ PurpleInputFunction function;
283
+ guint result;
284
+ gpointer data;
285
+ } PurpleGLibIOClosure;
286
+
287
+ static void purple_glib_io_destroy(gpointer data)
288
+ {
289
+ g_free(data);
290
+ }
291
+
292
+ static gboolean purple_glib_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data)
293
+ {
294
+ PurpleGLibIOClosure *closure = data;
295
+ PurpleInputCondition purple_cond = 0;
296
+
297
+ if (condition & PURPLE_GLIB_READ_COND)
298
+ purple_cond |= PURPLE_INPUT_READ;
299
+ if (condition & PURPLE_GLIB_WRITE_COND)
300
+ purple_cond |= PURPLE_INPUT_WRITE;
301
+
302
+ closure->function(closure->data, g_io_channel_unix_get_fd(source),
303
+ purple_cond);
304
+
305
+ return TRUE;
306
+ }
307
+
308
+ static guint glib_input_add(gint fd, PurpleInputCondition condition, PurpleInputFunction function,
309
+ gpointer data)
310
+ {
311
+ PurpleGLibIOClosure *closure = g_new0(PurpleGLibIOClosure, 1);
312
+ GIOChannel *channel;
313
+ GIOCondition cond = 0;
314
+
315
+ closure->function = function;
316
+ closure->data = data;
317
+
318
+ if (condition & PURPLE_INPUT_READ)
319
+ cond |= PURPLE_GLIB_READ_COND;
320
+ if (condition & PURPLE_INPUT_WRITE)
321
+ cond |= PURPLE_GLIB_WRITE_COND;
322
+
323
+ channel = g_io_channel_unix_new(fd);
324
+ closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond,
325
+ purple_glib_io_invoke, closure, purple_glib_io_destroy);
326
+
327
+ g_io_channel_unref(channel);
328
+ return closure->result;
329
+ }
330
+
331
+ static PurpleEventLoopUiOps glib_eventloops =
332
+ {
333
+ g_timeout_add,
334
+ g_source_remove,
335
+ glib_input_add,
336
+ g_source_remove,
337
+ NULL
338
+ };
339
+ /*** End of the eventloop functions. ***/
340
+
341
+ static gpointer
342
+ run_the_loop(gpointer data)
343
+ {
344
+ main_loop = g_main_loop_new(NULL, FALSE);
345
+ g_main_loop_run(main_loop);
346
+ }
347
+
348
+ static VALUE
349
+ rb_ruburple_init(VALUE self)
350
+ {
351
+ if (purple_get_core() == NULL) {
352
+ /* We do not want any debugging for now to keep the noise to a minimum. */
353
+ purple_debug_set_enabled(FALSE);
354
+
355
+ /* Set the uiops for the eventloop. If your client is glib-based, you can safely
356
+ * copy this verbatim. */
357
+ purple_eventloop_set_ui_ops(&glib_eventloops);
358
+
359
+ /* Now that all the essential stuff has been set, let's try to init the core. It's
360
+ * necessary to provide a non-NULL name for the current ui to the core. This name
361
+ * is used by stuff that depends on this ui, for example the ui-specific plugins. */
362
+ if (!purple_core_init(UI_ID)) {
363
+ /* Initializing the core failed. Terminate. */
364
+ fprintf(stderr,
365
+ "libpurple initialization failed. Dumping core.\n"
366
+ "Please report this!\n");
367
+ abort();
368
+ }
369
+
370
+ /* Create and load the buddylist. */
371
+ purple_set_blist(purple_blist_new());
372
+ purple_blist_load();
373
+
374
+ /* Load the preferences. */
375
+ purple_prefs_load();
376
+
377
+ /* Load the pounces. */
378
+ purple_pounces_load();
379
+
380
+ g_thread_create(run_the_loop, NULL, FALSE, NULL);
381
+ }
382
+ return Qnil;
383
+ }
384
+
385
+ static VALUE
386
+ rb_ruburple_quit(VALUE self)
387
+ {
388
+ if (purple_get_core() != NULL) {
389
+ g_main_loop_quit(main_loop);
390
+ purple_core_quit();
391
+ }
392
+ return Qnil;
393
+ }
394
+
395
+ static gpointer
396
+ ruburple_set_debug(gpointer data)
397
+ {
398
+ purple_debug_set_enabled(GBOOL(* ((VALUE *) data)));
399
+ return NULL;
400
+ }
401
+
402
+ static VALUE
403
+ rb_ruburple_set_debug(VALUE self, VALUE enabled)
404
+ {
405
+ gpointer return_value = call_and_get_result(ruburple_set_debug, (gpointer) (&enabled));
406
+ return Qnil;
407
+ }
408
+
409
+ static VALUE
410
+ rb_protocol_get_id(VALUE self)
411
+ {
412
+ PurplePlugin *plugin;
413
+ const gchar *id;
414
+ PURPLE_PLUGIN(self, plugin);
415
+ id = purple_plugin_get_id(plugin);
416
+ RETURN_QNIL_IF_NULL(id);
417
+ return rb_str_new2(id);
418
+ }
419
+
420
+ static VALUE
421
+ rb_protocol_get_summary(VALUE self)
422
+ {
423
+ PurplePlugin *plugin;
424
+ const gchar *summary;
425
+ PURPLE_PLUGIN(self, plugin);
426
+ summary = purple_plugin_get_summary(plugin);
427
+ RETURN_QNIL_IF_NULL(summary);
428
+ return rb_str_new2(summary);
429
+ }
430
+
431
+ static VALUE
432
+ rb_protocol_get_version(VALUE self)
433
+ {
434
+ PurplePlugin *plugin;
435
+ const gchar *version;
436
+ PURPLE_PLUGIN(self, plugin);
437
+ version = purple_plugin_get_version(plugin);
438
+ RETURN_QNIL_IF_NULL(version);
439
+ return rb_str_new2(version);
440
+ }
441
+
442
+ static VALUE
443
+ rb_protocol_get_name(VALUE self)
444
+ {
445
+ PurplePlugin *plugin;
446
+ const gchar *name;
447
+ PURPLE_PLUGIN(self, plugin);
448
+ name = purple_plugin_get_name(plugin);
449
+ RETURN_QNIL_IF_NULL(name);
450
+ return rb_str_new2(name);
451
+ }
452
+
453
+ static VALUE
454
+ rb_protocol_get_description(VALUE self)
455
+ {
456
+ PurplePlugin *plugin;
457
+ const gchar *description;
458
+ PURPLE_PLUGIN(self, plugin);
459
+ description = purple_plugin_get_description(plugin);
460
+ RETURN_QNIL_IF_NULL(description);
461
+ return rb_str_new2(description);
462
+ }
463
+
464
+ static VALUE
465
+ rb_protocol_get_author(VALUE self)
466
+ {
467
+ PurplePlugin *plugin;
468
+ const gchar *author;
469
+ PURPLE_PLUGIN(self, plugin);
470
+ author = purple_plugin_get_author(plugin);
471
+ RETURN_QNIL_IF_NULL(author);
472
+ return rb_str_new2(author);
473
+ }
474
+
475
+ static VALUE
476
+ rb_protocol_get_homepage(VALUE self)
477
+ {
478
+ PurplePlugin *plugin;
479
+ const gchar *homepage;
480
+ PURPLE_PLUGIN(self, plugin);
481
+ homepage = purple_plugin_get_homepage(plugin);
482
+ RETURN_QNIL_IF_NULL(homepage);
483
+ return rb_str_new2(homepage);
484
+ }
485
+
486
+ static gpointer
487
+ ruburple_get_protocols(gpointer data)
488
+ {
489
+ return (gpointer) purple_plugins_get_protocols();
490
+ }
491
+
492
+ static VALUE
493
+ rb_ruburple_get_protocols(VALUE self)
494
+ {
495
+ GList *iter;
496
+ VALUE return_value = rb_ary_new();
497
+
498
+ iter = (GList *) call_and_get_result(ruburple_get_protocols, NULL);
499
+
500
+ for (iter = purple_plugins_get_protocols(); iter; iter = iter->next) {
501
+ rb_ary_push(return_value, RB_RUBURPLE_PROTOCOL(iter->data));
502
+ }
503
+
504
+ return return_value;
505
+ }
506
+
507
+ static gpointer
508
+ ruburple_protocol_account_free(gpointer data)
509
+ {
510
+ PurpleAccount *account = (PurpleAccount *) data;
511
+ if (!purple_account_is_disconnected(account) && !account->disconnecting)
512
+ purple_account_disconnect(account);
513
+ purple_account_destroy(account);
514
+ return NULL;
515
+ }
516
+
517
+ static void
518
+ rb_ruburple_protocol_account_free(PurpleAccount *account)
519
+ {
520
+ call_and_get_result(ruburple_protocol_account_free, account);
521
+ }
522
+
523
+ static gpointer
524
+ ruburple_protocol_get_account(gpointer data)
525
+ {
526
+ gpointer *args = (gpointer *) data;
527
+ return (gpointer) purple_account_new((char *) args[0], (char *) args[1]);
528
+ }
529
+
530
+ static VALUE
531
+ rb_ruburple_protocol_get_account(VALUE self, VALUE name)
532
+ {
533
+ PurplePlugin *plugin;
534
+ gpointer *args = g_new(gpointer, 2);
535
+ VALUE return_value;
536
+
537
+ Check_Type(name, T_STRING);
538
+ PURPLE_PLUGIN(self, plugin);
539
+
540
+ args[0] = (gpointer) RSTRING(name)->ptr;
541
+ args[1] = (gpointer) plugin->info->id;
542
+
543
+ return_value = RB_RUBURPLE_PROTOCOL_ACCOUNT_gc((PurpleAccount *) call_and_get_result(ruburple_protocol_get_account, args));
544
+
545
+ g_free(args);
546
+
547
+ return return_value;
548
+ }
549
+
550
+ static gpointer
551
+ ruburple_protocol_account_set_password(gpointer data)
552
+ {
553
+ gpointer *args = (gpointer *) data;
554
+ purple_account_set_password((PurpleAccount *) args[0], (char *) args[1]);
555
+ return NULL;
556
+ }
557
+
558
+ static VALUE
559
+ rb_ruburple_protocol_account_set_password(VALUE self, VALUE password)
560
+ {
561
+ PurpleAccount *account;
562
+ gpointer *args = g_new(gpointer, 2);
563
+
564
+ Check_Type(password, T_STRING);
565
+ PURPLE_ACCOUNT(self, account);
566
+ args[0] = (gpointer) account;
567
+ args[1] = (gpointer) RSTRING(password)->ptr;
568
+
569
+ call_and_get_result(ruburple_protocol_account_set_password, args);
570
+
571
+ g_free(args);
572
+
573
+ return Qnil;
574
+ }
575
+
576
+ static gpointer
577
+ ruburple_protocol_account_connect(gpointer data)
578
+ {
579
+ PurpleAccount *account = (PurpleAccount *) data;
580
+ purple_account_set_enabled(account, UI_ID, TRUE);
581
+ return NULL;
582
+ }
583
+
584
+ static VALUE
585
+ rb_ruburple_protocol_account_connect(VALUE self)
586
+ {
587
+ PurpleAccount *account;
588
+ PURPLE_ACCOUNT(self, account);
589
+
590
+ call_and_get_result(ruburple_protocol_account_connect, account);
591
+
592
+ return Qnil;
593
+ }
594
+
595
+ static gpointer
596
+ ruburple_protocol_account_set_savedstatus(gpointer data)
597
+ {
598
+ gpointer *args = (gpointer *) data;
599
+ purple_savedstatus_activate_for_account((PurpleSavedStatus *) args[0], (PurpleAccount *) args[1]);
600
+ return NULL;
601
+ }
602
+
603
+ static VALUE
604
+ rb_ruburple_protocol_account_set_savedstatus(VALUE self, VALUE savedstatus_value)
605
+ {
606
+ PurpleAccount *account;
607
+ PurpleSavedStatus *savedstatus;
608
+ gpointer *args = g_new(gpointer, 2);
609
+
610
+ PURPLE_ACCOUNT(self, account);
611
+ PURPLE_SAVEDSTATUS(savedstatus_value, savedstatus);
612
+
613
+ args[0] = (gpointer) savedstatus;
614
+ args[1] = (gpointer) account;
615
+
616
+ call_and_get_result(ruburple_protocol_account_set_savedstatus, args);
617
+
618
+ g_free(args);
619
+
620
+ return Qnil;
621
+ }
622
+
623
+ static gpointer
624
+ ruburple_protocol_account_savedstatus_alloc(gpointer data)
625
+ {
626
+ return (gpointer) purple_savedstatus_new(NULL, PURPLE_STATUS_UNSET);
627
+ }
628
+
629
+ static VALUE
630
+ rb_ruburple_protocol_account_savedstatus_alloc(VALUE klass)
631
+ {
632
+ PurpleSavedStatus *savedstatus = (PurpleSavedStatus *) call_and_get_result(ruburple_protocol_account_savedstatus_alloc, NULL);
633
+ return Data_Wrap_Struct(klass, NULL, free, savedstatus);
634
+ }
635
+
636
+ static gpointer
637
+ ruburple_protocol_account_savedstatus_initialize(gpointer data)
638
+ {
639
+ gpointer *args = (gpointer *) data;
640
+ purple_savedstatus_set_type((PurpleSavedStatus *) args[0], NUM2INT(*( (VALUE *) args[1])));
641
+ }
642
+
643
+ static VALUE
644
+ rb_ruburple_protocol_account_savedstatus_initialize(VALUE self, VALUE status_constant)
645
+ {
646
+ PurpleSavedStatus *savedstatus;
647
+ gpointer *args = g_new(gpointer, 2);
648
+
649
+ Check_Type(status_constant, T_FIXNUM);
650
+ PURPLE_SAVEDSTATUS(self, savedstatus);
651
+
652
+ args[0] = (gpointer) savedstatus;
653
+ args[1] = (gpointer) (&status_constant);
654
+
655
+ call_and_get_result(ruburple_protocol_account_savedstatus_initialize, args);
656
+
657
+ g_free(args);
658
+
659
+ return Qnil;
660
+ }
661
+
662
+ static VALUE
663
+ get_ruby_instance_from_subtype(PurpleValue *value, gpointer data, int i, char *signal_name)
664
+ {
665
+ switch (purple_value_get_subtype(value)) {
666
+ case PURPLE_SUBTYPE_UNKNOWN:
667
+ FATAL("argument %d of callback from signal %s is of PURPLE_TYPE_SUBTYPE:PURPLE_TYPE_UNKNOWN",
668
+ i,
669
+ signal_name);
670
+ break;
671
+ case PURPLE_SUBTYPE_ACCOUNT:
672
+ return(RB_RUBURPLE_PROTOCOL_ACCOUNT((PurpleAccount *) data));
673
+ break;
674
+ case PURPLE_SUBTYPE_BLIST:
675
+ return(RB_RUBURPLE_BLIST((PurpleBuddyList *) data));
676
+ break;
677
+ case PURPLE_SUBTYPE_BLIST_BUDDY:
678
+ return(RB_RUBURPLE_BLIST_BUDDY((PurpleBuddy *) data));
679
+ break;
680
+ case PURPLE_SUBTYPE_BLIST_GROUP:
681
+ return(RB_RUBURPLE_BLIST_GROUP((PurpleGroup *) data));
682
+ break;
683
+ case PURPLE_SUBTYPE_BLIST_CHAT:
684
+ return(RB_RUBURPLE_PROTOCOL_ACCOUNT_CHAT((PurpleChat *) data));
685
+ break;
686
+ case PURPLE_SUBTYPE_BUDDY_ICON:
687
+ return(RB_RUBURPLE_BLIST_BUDDY_ICON((PurpleBuddyIcon *) data));
688
+ break;
689
+ case PURPLE_SUBTYPE_CONNECTION:
690
+ return(RB_RUBURPLE_PROTOCOL_CONNECTION((PurpleConnection *) data));
691
+ break;
692
+ case PURPLE_SUBTYPE_CONVERSATION:
693
+ return(RB_RUBURPLE_PROTOCOL_ACCOUNT_CONVERSATION((PurpleConversation *) data));
694
+ break;
695
+ case PURPLE_SUBTYPE_PLUGIN:
696
+ return(RB_RUBURPLE_PLUGIN((PurplePlugin *) data));
697
+ break;
698
+ case PURPLE_SUBTYPE_BLIST_NODE:
699
+ return(RB_RUBURPLE_BLIST_NODE((PurpleBlistNode *) data));
700
+ break;
701
+ case PURPLE_SUBTYPE_CIPHER:
702
+ return(RB_RUBURPLE_CIPHER((PurpleCipher *) data));
703
+ break;
704
+ case PURPLE_SUBTYPE_STATUS:
705
+ return(RB_RUBURPLE_BLIST_STATUS((PurpleStatus *) data));
706
+ break;
707
+ case PURPLE_SUBTYPE_LOG:
708
+ return(RB_RUBURPLE_LOG((PurpleLog *) data));
709
+ break;
710
+ case PURPLE_SUBTYPE_XFER:
711
+ return(RB_RUBURPLE_PROTOCOL_ACCOUNT_TRANSFER((PurpleXfer *) data));
712
+ break;
713
+ case PURPLE_SUBTYPE_SAVEDSTATUS:
714
+ return(RB_RUBURPLE_PROTOCOL_ACCOUNT_SAVEDSTATUS((PurpleSavedStatus *) data));
715
+ break;
716
+ case PURPLE_SUBTYPE_XMLNODE:
717
+ return(RB_RUBURPLE_XMLNODE((xmlnode *) data));
718
+ break;
719
+ case PURPLE_SUBTYPE_USERINFO:
720
+ return(RB_RUBURPLE_USERINFO((PurpleNotifyUserInfo *) data));
721
+ break;
722
+ case PURPLE_SUBTYPE_STORED_IMAGE:
723
+ return(RB_RUBURPLE_STOREDIMAGE((PurpleStoredImage *) data));
724
+ break;
725
+ default:
726
+ FATAL("argument %d of callback from signal %s is of a completely unknown PURPLE_TYPE_SUBTYPE %d",
727
+ i,
728
+ signal_name,
729
+ purple_value_get_subtype(value));
730
+ break;
731
+ }
732
+ }
733
+
734
+ static void
735
+ ruburple_callback(va_list args, void *data)
736
+ {
737
+ RuburpleSignalHandler *handler = (RuburpleSignalHandler *) data;
738
+ void *ret_val;
739
+ int value_count;
740
+ int i;
741
+ PurpleValue *ret_value, **values;
742
+ IncomingRuburpleEvent event;
743
+ IncomingRuburpleEvent *event_pointer = &event;
744
+ VALUE *ruby_args;
745
+ gpointer next_arg;
746
+
747
+ purple_signal_get_values(handler->handle, handler->signal,
748
+ &ret_value, &value_count, &values);
749
+
750
+ ruby_args = g_new(VALUE, value_count);
751
+
752
+ for (i = 0; i < value_count; i++) {
753
+ if (purple_value_is_outgoing(values[i])) {
754
+ switch (purple_value_get_type(values[i])) {
755
+ case PURPLE_TYPE_UNKNOWN: /**< Unknown type. */
756
+ FATAL("argument %d of callback from signal %s is of PURPLE_TYPE_UNKNOWN",
757
+ i,
758
+ handler->signal);
759
+ break;
760
+ case PURPLE_TYPE_SUBTYPE: /**< Subtype. */
761
+ if ((next_arg = (gpointer) va_arg(args, gpointer *)) == NULL) {
762
+ ruby_args[i] = Qnil;
763
+ } else {
764
+ ruby_args[i] = get_ruby_instance_from_subtype(values[i], *( (gpointer *) next_arg), i, handler->signal);
765
+ }
766
+ break;
767
+ case PURPLE_TYPE_CHAR: /**< Character. */
768
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
769
+ ruby_args[i] = Qnil;
770
+ else
771
+ ruby_args[i] = INT2NUM(*(char *) next_arg);
772
+ break;
773
+ case PURPLE_TYPE_UCHAR: /**< Unsigned character. */
774
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
775
+ ruby_args[i] = Qnil;
776
+ else
777
+ ruby_args[i] = INT2NUM(*(unsigned char *) next_arg);
778
+ break;
779
+ case PURPLE_TYPE_BOOLEAN: /**< Boolean. */
780
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
781
+ ruby_args[i] = Qnil;
782
+ else
783
+ ruby_args[i] = (*(gboolean *) next_arg == TRUE ? Qtrue : Qfalse);
784
+ break;
785
+ case PURPLE_TYPE_SHORT: /**< Short integer. */
786
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
787
+ ruby_args[i] = Qnil;
788
+ else
789
+ ruby_args[i] = INT2NUM(*(short *) next_arg);
790
+ break;
791
+ case PURPLE_TYPE_USHORT: /**< Unsigned short integer. */
792
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
793
+ ruby_args[i] = Qnil;
794
+ else
795
+ ruby_args[i] = INT2NUM(*(unsigned short *) next_arg);
796
+ break;
797
+ case PURPLE_TYPE_INT: /**< Integer. */
798
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
799
+ ruby_args[i] = Qnil;
800
+ else
801
+ ruby_args[i] = INT2NUM(*(int *) next_arg);
802
+ break;
803
+ case PURPLE_TYPE_UINT: /**< Unsigned integer. */
804
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
805
+ ruby_args[i] = Qnil;
806
+ else
807
+ ruby_args[i] = INT2NUM(*(unsigned int *) next_arg);
808
+ break;
809
+ case PURPLE_TYPE_LONG: /**< Long integer. */
810
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
811
+ ruby_args[i] = Qnil;
812
+ else
813
+ ruby_args[i] = INT2NUM(*(long *) next_arg);
814
+ break;
815
+ case PURPLE_TYPE_ULONG: /**< Unsigned long integer. */
816
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
817
+ ruby_args[i] = Qnil;
818
+ else
819
+ ruby_args[i] = INT2NUM(*(unsigned long *) next_arg);
820
+ break;
821
+ case PURPLE_TYPE_INT64: /**< 64-bit integer. */
822
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
823
+ ruby_args[i] = Qnil;
824
+ else
825
+ ruby_args[i] = INT2NUM(*(gint64 *) next_arg);
826
+ break;
827
+ case PURPLE_TYPE_UINT64: /**< 64-bit unsigned integer. */
828
+ if ((next_arg = va_arg(args, gpointer)) == NULL)
829
+ ruby_args[i] = Qnil;
830
+ else
831
+ ruby_args[i] = INT2NUM(*(guint64 *) next_arg);
832
+ break;
833
+ case PURPLE_TYPE_STRING: /**< String. */
834
+ if ((next_arg = va_arg(args, gpointer *)) == NULL)
835
+ ruby_args[i] = Qnil;
836
+ else
837
+ ruby_args[i] = rb_str_new2(*(char **) next_arg);
838
+ break;
839
+ case PURPLE_TYPE_OBJECT: /**< Object pointer. */
840
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_OBJECT which I dont know what the hell to do with",
841
+ i);
842
+ break;
843
+ case PURPLE_TYPE_POINTER: /**< Generic pointer. */
844
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_POINTER which I dont know what the hell to do with",
845
+ i);
846
+ break;
847
+ case PURPLE_TYPE_ENUM: /**< Enum. */
848
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_ENUM which I dont know what the hell to do with",
849
+ i);
850
+ break;
851
+ case PURPLE_TYPE_BOXED: /**< Boxed pointer with specific type. */
852
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_BOXED which I dont know what the hell to do with",
853
+ i);
854
+ break;
855
+ default:
856
+ FATAL("argument %d of callback from signal %s is of a completely unknown type %d",
857
+ i,
858
+ handler->signal,
859
+ purple_value_get_type(values[i]));
860
+ break;
861
+ }
862
+ } else {
863
+ switch (purple_value_get_type(values[i])) {
864
+ case PURPLE_TYPE_UNKNOWN: /**< Unknown type. */
865
+ FATAL("argument %d of callback from signal %s is of PURPLE_TYPE_UNKNOWN",
866
+ i,
867
+ handler->signal);
868
+ break;
869
+ case PURPLE_TYPE_SUBTYPE: /**< Subtype. */
870
+ if ((next_arg = va_arg(args, gpointer)) == NULL) {
871
+ ruby_args[i] = Qnil;
872
+ } else {
873
+ ruby_args[i] = get_ruby_instance_from_subtype(values[i], next_arg, i, handler->signal);
874
+ }
875
+ break;
876
+ default:
877
+ switch (purple_value_get_type(values[i])) {
878
+ case PURPLE_TYPE_BOOLEAN: /**< Boolean. */
879
+ ruby_args[i] = va_arg(args, gboolean) == TRUE ? Qtrue : Qfalse;
880
+ break;
881
+ case PURPLE_TYPE_INT: /**< Integer. */
882
+ ruby_args[i] = INT2NUM(va_arg(args, int));
883
+ break;
884
+ case PURPLE_TYPE_UINT: /**< Unsigned integer. */
885
+ ruby_args[i] = INT2NUM(va_arg(args, unsigned int));
886
+ break;
887
+ case PURPLE_TYPE_LONG: /**< Long integer. */
888
+ ruby_args[i] = INT2NUM(va_arg(args, long));
889
+ break;
890
+ case PURPLE_TYPE_ULONG: /**< Unsigned long integer. */
891
+ ruby_args[i] = INT2NUM(va_arg(args, unsigned long));
892
+ break;
893
+ case PURPLE_TYPE_INT64: /**< 64-bit integer. */
894
+ ruby_args[i] = INT2NUM(va_arg(args, gint64));
895
+ break;
896
+ case PURPLE_TYPE_UINT64: /**< 64-bit unsigned integer. */
897
+ ruby_args[i] = INT2NUM(va_arg(args, guint64));
898
+ break;
899
+ case PURPLE_TYPE_STRING: /**< String. */
900
+ ruby_args[i] = rb_str_new2(va_arg(args, char *));
901
+ break;
902
+ case PURPLE_TYPE_OBJECT: /**< Object pointer. */
903
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_OBJECT which I dont know what the hell to do with",
904
+ i);
905
+ break;
906
+ case PURPLE_TYPE_POINTER: /**< Generic pointer. */
907
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_POINTER which I dont know what the hell to do with",
908
+ i);
909
+ break;
910
+ case PURPLE_TYPE_ENUM: /**< Enum. */
911
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_ENUM which I dont know what the hell to do with",
912
+ i);
913
+ break;
914
+ case PURPLE_TYPE_BOXED: /**< Boxed pointer with specific type. */
915
+ FATAL("argument %d of callback from signal %s is of type PURPLE_TYPE_BOXED which I dont know what the hell to do with",
916
+ i);
917
+ break;
918
+ default:
919
+ FATAL("argument %d of callback from signal %s is of a completely unknown type %d",
920
+ i,
921
+ handler->signal,
922
+ purple_value_get_type(values[i]));
923
+ break;
924
+ }
925
+ }
926
+ }
927
+ }
928
+
929
+ event.receiver = handler->callable;
930
+ event.method = call_method_id;
931
+ event.argc = value_count;
932
+ event.argv = ruby_args;
933
+ event.lock = g_mutex_new();
934
+ event.flag = g_cond_new();
935
+
936
+ g_mutex_lock(event.lock);
937
+
938
+ write(purple_event_queue[1], (char *) &event_pointer, sizeof(IncomingRuburpleEvent *));
939
+
940
+ g_cond_wait(event.flag, event.lock);
941
+
942
+ g_mutex_unlock(event.lock);
943
+
944
+ g_mutex_free(event.lock);
945
+ g_cond_free(event.flag);
946
+ g_free(event.argv);
947
+ }
948
+
949
+ static VALUE
950
+ rb_ruburple_read_event(VALUE self)
951
+ {
952
+ IncomingRuburpleEvent *event;
953
+ VALUE return_value;
954
+ int i;
955
+
956
+ read(purple_event_queue[0], (char *) &event, sizeof(IncomingRuburpleEvent *));
957
+
958
+ return_value = rb_funcall2(event->receiver, event->method, event->argc, event->argv);
959
+
960
+ g_mutex_lock(event->lock);
961
+ g_cond_signal(event->flag);
962
+ g_mutex_unlock(event->lock);
963
+
964
+ return return_value;
965
+ }
966
+
967
+ static gpointer
968
+ ruburple_signal_connect_vargs(gpointer data)
969
+ {
970
+ RuburpleSignalHandler *handler = (RuburpleSignalHandler *) data;
971
+ purple_signal_connect_vargs(handler->handle, handler->signal, (gpointer) handler->callable, PURPLE_CALLBACK(ruburple_callback), (gpointer) handler);
972
+ return NULL;
973
+ }
974
+
975
+ static VALUE
976
+ rb_ruburple_subscribe(VALUE self, VALUE handle_value, VALUE signal_name, VALUE callable)
977
+ {
978
+ VALUE return_value;
979
+ gpointer handle;
980
+ GPOINTER(handle_value, handle);
981
+ RuburpleSignalHandler *handler = ruburple_signal_handler_new(handle,
982
+ RSTRING(signal_name)->ptr,
983
+ callable);
984
+
985
+ call_and_get_result(ruburple_signal_connect_vargs, (gpointer) handler);
986
+
987
+ return_value = RB_RUBURPLE_SUBSCRIPTION_gc(handler);
988
+
989
+ rb_gc_register_address(&return_value);
990
+
991
+ return return_value;
992
+ }
993
+
994
+ static gpointer
995
+ ruburple_signal_disconnect(gpointer data)
996
+ {
997
+ RuburpleSignalHandler *handler = (RuburpleSignalHandler *) data;
998
+ purple_signal_disconnect(handler->handle, handler->signal, (gpointer) handler->callable, PURPLE_CALLBACK(ruburple_callback));
999
+ return NULL;
1000
+ }
1001
+
1002
+ static VALUE
1003
+ rb_ruburple_subscription_unsubscribe(VALUE self)
1004
+ {
1005
+ RuburpleSignalHandler *handler;
1006
+ RUBURPLE_SIGNAL_HANDLER(self, handler);
1007
+
1008
+ call_and_get_result(ruburple_signal_disconnect, (gpointer) handler);
1009
+
1010
+ rb_gc_unregister_address(&self);
1011
+
1012
+ return Qnil;
1013
+ }
1014
+
1015
+ static VALUE
1016
+ rb_ruburple_protocol_account_get_connection(VALUE self)
1017
+ {
1018
+ PurpleAccount *account;
1019
+ PurpleConnection *connection;
1020
+ PURPLE_ACCOUNT(self, account);
1021
+ connection = purple_account_get_connection(account);
1022
+ RETURN_QNIL_IF_NULL(connection);
1023
+ return RB_RUBURPLE_PROTOCOL_CONNECTION(connection);
1024
+ }
1025
+
1026
+ static gpointer
1027
+ ruburple_serv_send_im(gpointer data)
1028
+ {
1029
+ gpointer *args = (gpointer *) data;
1030
+ int *rval = g_new(int, 1);
1031
+ *rval = serv_send_im((PurpleConnection *) args[0], (char *) args[1], (char *) args[2], * (int *) args[3]);
1032
+ return (gpointer) rval;
1033
+ }
1034
+
1035
+ static VALUE
1036
+ rb_ruburple_protocol_connection_send_im(int argc, VALUE *argv, VALUE self)
1037
+ {
1038
+ PurpleConnection *connection;
1039
+ int flags = 0;
1040
+ gpointer tmp;
1041
+ gpointer args[4];
1042
+ int rval;
1043
+
1044
+ if (argc > 3)
1045
+ rb_raise(rb_eRuntimeError, "Connection#send_im(RECIPIENT, MESSAGE, FLAGS = 0) takes at most 3 arguments");
1046
+ if (argc == 3) {
1047
+ Check_Type(argv[2], T_FIXNUM);
1048
+ flags = NUM2INT(argv[2]);
1049
+ }
1050
+ if (argc >= 2) {
1051
+ Check_Type(argv[1], T_STRING);
1052
+ Check_Type(argv[0], T_STRING);
1053
+ } else {
1054
+ rb_raise(rb_eRuntimeError, "Connection#send_im(RECIPIENT, MESSAGE, FLAGS = 0) takes at least 2 arguments");
1055
+ }
1056
+
1057
+ PURPLE_CONNECTION(self, connection);
1058
+
1059
+ args[0] = (gpointer) connection;
1060
+ args[1] = (gpointer) RSTRING(argv[0])->ptr;
1061
+ args[2] = (gpointer) RSTRING(argv[1])->ptr;
1062
+ args[3] = (gpointer) &flags;
1063
+
1064
+ tmp = call_and_get_result(ruburple_serv_send_im, args);
1065
+ rval = * (int *) tmp;
1066
+ g_free(tmp);
1067
+
1068
+ return INT2NUM(rval);
1069
+ }
1070
+
1071
+ static gpointer
1072
+ ruburple_protocol_connection_close(gpointer data)
1073
+ {
1074
+ PurpleConnection *connection = (PurpleConnection *) data;
1075
+ PurpleAccount *account = purple_connection_get_account(connection);
1076
+ if (!purple_account_is_disconnected(account) && !account->disconnecting)
1077
+ purple_account_disconnect(account);
1078
+ return NULL;
1079
+ }
1080
+
1081
+ static VALUE
1082
+ rb_ruburple_protocol_connection_close(VALUE self)
1083
+ {
1084
+ PurpleConnection *connection;
1085
+ PURPLE_CONNECTION(self, connection);
1086
+ call_and_get_result(ruburple_protocol_connection_close, connection);
1087
+ return Qnil;
1088
+ }
1089
+
1090
+ static gpointer
1091
+ ruburple_protocol_account_is_connected(gpointer data)
1092
+ {
1093
+ PurpleAccount *account = (PurpleAccount *) data;
1094
+ gboolean *rval = g_new(gboolean, 1);
1095
+ *rval = purple_account_is_connected(account);
1096
+ return rval;
1097
+ }
1098
+
1099
+ static VALUE
1100
+ rb_ruburple_protocol_account_is_connected(VALUE self)
1101
+ {
1102
+ PurpleAccount *account;
1103
+ gboolean *tmp;
1104
+ VALUE rval;
1105
+ PURPLE_ACCOUNT(self, account);
1106
+ tmp = (gboolean *) call_and_get_result(ruburple_protocol_account_is_connected, account);
1107
+ rval = BOOL(*tmp);
1108
+ g_free(tmp);
1109
+ return rval;
1110
+ }
1111
+
1112
+ #ifdef __cplusplus
1113
+ extern "C" {
1114
+ #endif
1115
+ void Init_ruburple_ext() {
1116
+ VALUE io_class = rb_define_class("IO", rb_cObject);
1117
+ VALUE new_method = rb_intern("new");
1118
+
1119
+ if (pipe(purple_event_queue) == -1)
1120
+ rb_raise(rb_eRuntimeError, "error creating event pipe from libpurple to ruby: %s", strerror(errno));
1121
+
1122
+ call_method_id = rb_intern("call");
1123
+ idle_handler_method_id = rb_intern("_idle_handler");
1124
+
1125
+ rb_ruburple = rb_define_module("Ruburple");
1126
+ rb_define_singleton_method(rb_ruburple, "quit", rb_ruburple_quit, 0);
1127
+ rb_define_singleton_method(rb_ruburple, "debug=", rb_ruburple_set_debug, 1);
1128
+ rb_define_singleton_method(rb_ruburple, "protocols", rb_ruburple_get_protocols, 0);
1129
+ rb_define_singleton_method(rb_ruburple, "init", rb_ruburple_init, 0);
1130
+ rb_define_singleton_method(rb_ruburple, "_subscribe", rb_ruburple_subscribe, 3);
1131
+ rb_define_singleton_method(rb_ruburple, "_read_event", rb_ruburple_read_event, 0);
1132
+ rb_define_const(rb_ruburple, "MESSAGE_SEND", INT2NUM(PURPLE_MESSAGE_SEND)); /**< Outgoing message. */
1133
+ rb_define_const(rb_ruburple, "MESSAGE_RECV", INT2NUM(PURPLE_MESSAGE_RECV)); /**< Incoming message. */
1134
+ rb_define_const(rb_ruburple, "MESSAGE_SYSTEM", INT2NUM(PURPLE_MESSAGE_SYSTEM)); /**< System message. */
1135
+ rb_define_const(rb_ruburple, "MESSAGE_AUTO_RESP", INT2NUM(PURPLE_MESSAGE_AUTO_RESP)); /**< Auto response. */
1136
+ rb_define_const(rb_ruburple, "MESSAGE_ACTIVE_ONLY", INT2NUM(PURPLE_MESSAGE_ACTIVE_ONLY)); /**< Hint to the UI that this
1137
+ message should not be
1138
+ shown in conversations
1139
+ which are only open for
1140
+ internal UI purposes
1141
+ (e.g. for contact-aware
1142
+ conversions). */
1143
+ rb_define_const(rb_ruburple, "MESSAGE_NICK", INT2NUM(PURPLE_MESSAGE_NICK)); /**< Contains your nick. */
1144
+ rb_define_const(rb_ruburple, "MESSAGE_NO_LOG", INT2NUM(PURPLE_MESSAGE_NO_LOG)); /**< Do not log. */
1145
+ rb_define_const(rb_ruburple, "MESSAGE_WHISPER", INT2NUM(PURPLE_MESSAGE_WHISPER)); /**< Whispered message. */
1146
+ rb_define_const(rb_ruburple, "MESSAGE_ERROR", INT2NUM(PURPLE_MESSAGE_ERROR)); /**< Error message. */
1147
+ rb_define_const(rb_ruburple, "MESSAGE_DELAYED", INT2NUM(PURPLE_MESSAGE_DELAYED)); /**< Delayed message. */
1148
+ rb_define_const(rb_ruburple, "MESSAGE_RAW", INT2NUM(PURPLE_MESSAGE_RAW)); /**< "Raw" message - don't
1149
+ apply formatting */
1150
+ rb_define_const(rb_ruburple, "MESSAGE_IMAGES", INT2NUM(PURPLE_MESSAGE_IMAGES)); /**< Message contains images */
1151
+ rb_define_const(rb_ruburple, "MESSAGE_NOTIFY", INT2NUM(PURPLE_MESSAGE_NOTIFY)); /**< Message is a notification */
1152
+
1153
+ rb_define_const(rb_ruburple, "HANDLE_ACCOUNTS", RB_RUBURPLE_POINTER(purple_accounts_get_handle()));
1154
+ rb_define_const(rb_ruburple, "HANDLE_CONNECTIONS", RB_RUBURPLE_POINTER(purple_connections_get_handle()));
1155
+ rb_define_const(rb_ruburple, "HANDLE_CONVERSATIONS", RB_RUBURPLE_POINTER(purple_conversations_get_handle()));
1156
+ rb_define_const(rb_ruburple, "HANDLE_BLIST", RB_RUBURPLE_POINTER(purple_blist_get_handle()));
1157
+ rb_define_const(rb_ruburple, "HANDLE_CIPHERS", RB_RUBURPLE_POINTER(purple_ciphers_get_handle()));
1158
+ rb_define_const(rb_ruburple, "HANDLE_CORE", RB_RUBURPLE_POINTER(purple_get_core()));
1159
+ rb_define_const(rb_ruburple, "HANDLE_LOG", RB_RUBURPLE_POINTER(purple_log_get_handle()));
1160
+ rb_define_const(rb_ruburple, "HANDLE_PLUGINS", RB_RUBURPLE_POINTER(purple_plugins_get_handle()));
1161
+ rb_define_const(rb_ruburple, "HANDLE_SAVEDSTATUSES", RB_RUBURPLE_POINTER(purple_savedstatuses_get_handle()));
1162
+ rb_define_const(rb_ruburple, "HANDLE_XFERS", RB_RUBURPLE_POINTER(purple_xfers_get_handle()));
1163
+ rb_define_const(rb_ruburple, "EVENT_INPUT", rb_funcall(io_class, new_method, 1, INT2NUM(purple_event_queue[0])));
1164
+
1165
+ rb_ruburple_plugin = rb_define_class_under(rb_ruburple, "Plugin", rb_cObject);
1166
+
1167
+ rb_ruburple_protocol = rb_define_class_under(rb_ruburple, "Protocol", rb_ruburple_plugin);
1168
+ rb_define_method(rb_ruburple_protocol, "get_account", rb_ruburple_protocol_get_account, 1);
1169
+ rb_define_method(rb_ruburple_protocol, "id", rb_protocol_get_id, 0);
1170
+ rb_define_method(rb_ruburple_protocol, "name", rb_protocol_get_name, 0);
1171
+ rb_define_method(rb_ruburple_protocol, "version", rb_protocol_get_version, 0);
1172
+ rb_define_method(rb_ruburple_protocol, "summary", rb_protocol_get_summary, 0);
1173
+ rb_define_method(rb_ruburple_protocol, "description", rb_protocol_get_description, 0);
1174
+ rb_define_method(rb_ruburple_protocol, "author", rb_protocol_get_author, 0);
1175
+ rb_define_method(rb_ruburple_protocol, "homepage", rb_protocol_get_homepage, 0);
1176
+
1177
+ rb_ruburple_protocol_account = rb_define_class_under(rb_ruburple, "Account", rb_cObject);
1178
+ rb_define_method(rb_ruburple_protocol_account, "password=", rb_ruburple_protocol_account_set_password, 1);
1179
+ rb_define_method(rb_ruburple_protocol_account, "connect", rb_ruburple_protocol_account_connect, 0);
1180
+ rb_define_method(rb_ruburple_protocol_account, "savedstatus=", rb_ruburple_protocol_account_set_savedstatus, 1);
1181
+ rb_define_method(rb_ruburple_protocol_account, "connection", rb_ruburple_protocol_account_get_connection, 0);
1182
+ rb_define_method(rb_ruburple_protocol_account, "connected?", rb_ruburple_protocol_account_is_connected, 0);
1183
+
1184
+ rb_ruburple_protocol_account_conversation = rb_define_class_under(rb_ruburple_protocol_account, "Conversation", rb_cObject);
1185
+
1186
+ rb_ruburple_protocol_account_savedstatus = rb_define_class_under(rb_ruburple_protocol_account, "SavedStatus", rb_cObject);
1187
+ rb_define_alloc_func(rb_ruburple_protocol_account_savedstatus, rb_ruburple_protocol_account_savedstatus_alloc);
1188
+ rb_define_private_method(rb_ruburple_protocol_account_savedstatus, "initialize", rb_ruburple_protocol_account_savedstatus_initialize, 1);
1189
+
1190
+ rb_ruburple_blist = rb_define_class_under(rb_ruburple, "BuddyList", rb_cObject);
1191
+
1192
+ rb_ruburple_blist_status = rb_define_class_under(rb_ruburple_blist, "Status", rb_cObject);
1193
+ rb_define_const(rb_ruburple_blist_status, "STATUS_UNSET", INT2NUM(PURPLE_STATUS_UNSET));
1194
+ rb_define_const(rb_ruburple_blist_status, "STATUS_OFFLINE", INT2NUM(PURPLE_STATUS_OFFLINE));
1195
+ rb_define_const(rb_ruburple_blist_status, "STATUS_AVAILABLE", INT2NUM(PURPLE_STATUS_AVAILABLE));
1196
+ rb_define_const(rb_ruburple_blist_status, "STATUS_UNAVAILABLE", INT2NUM(PURPLE_STATUS_UNAVAILABLE));
1197
+ rb_define_const(rb_ruburple_blist_status, "STATUS_INVISIBLE", INT2NUM(PURPLE_STATUS_INVISIBLE));
1198
+ rb_define_const(rb_ruburple_blist_status, "STATUS_AWAY", INT2NUM(PURPLE_STATUS_AWAY));
1199
+ rb_define_const(rb_ruburple_blist_status, "STATUS_EXTENDED_AWAY", INT2NUM(PURPLE_STATUS_EXTENDED_AWAY));
1200
+ rb_define_const(rb_ruburple_blist_status, "STATUS_MOBILE", INT2NUM(PURPLE_STATUS_MOBILE));
1201
+
1202
+ rb_ruburple_protocol_connection = rb_define_class_under(rb_ruburple_protocol, "Connection", rb_cObject);
1203
+ rb_define_method(rb_ruburple_protocol_connection, "send_im", rb_ruburple_protocol_connection_send_im, -1);
1204
+ rb_define_method(rb_ruburple_protocol_connection, "close", rb_ruburple_protocol_connection_close, 0);
1205
+
1206
+ rb_ruburple_protocol_account_transfer = rb_define_class_under(rb_ruburple_protocol_account, "Transfer", rb_cObject);
1207
+
1208
+ rb_ruburple_blist_node = rb_define_class_under(rb_ruburple_blist, "Node", rb_cObject);
1209
+
1210
+ rb_ruburple_blist_buddy = rb_define_class_under(rb_ruburple_blist, "Buddy", rb_cObject);
1211
+
1212
+ rb_ruburple_blist_group = rb_define_class_under(rb_ruburple_blist, "Group", rb_cObject);
1213
+
1214
+ rb_ruburple_blist_buddy_icon = rb_define_class_under(rb_ruburple_blist, "BuddyIcon", rb_cObject);
1215
+
1216
+ rb_ruburple_handle = rb_define_class_under(rb_ruburple, "Handle", rb_cObject);
1217
+
1218
+ rb_ruburple_cipher = rb_define_class_under(rb_ruburple, "Cipher", rb_cObject);
1219
+
1220
+ rb_ruburple_log = rb_define_class_under(rb_ruburple, "Log", rb_cObject);
1221
+
1222
+ rb_ruburple_xmlnode = rb_define_class_under(rb_ruburple, "XMLNode", rb_cObject);
1223
+
1224
+ rb_ruburple_userinfo = rb_define_class_under(rb_ruburple, "UserInfo", rb_cObject);
1225
+
1226
+ rb_ruburple_storedimage = rb_define_class_under(rb_ruburple, "StoredImage", rb_cObject);
1227
+
1228
+ rb_ruburple_subscription = rb_define_class_under(rb_ruburple, "Subscription", rb_cObject);
1229
+ rb_define_method(rb_ruburple_subscription, "unsubscribe", rb_ruburple_subscription_unsubscribe, 0);
1230
+
1231
+ rb_ruburple_pointer = rb_define_class_under(rb_ruburple, "Pointer", rb_cObject);
1232
+
1233
+ g_thread_init(NULL);
1234
+
1235
+ }
1236
+ #ifdef __cplusplus
1237
+ }
1238
+ #endif
1239
+