ruburple 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+