yong-purple_ruby 0.4.1 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +22 -8
- data/Rakefile +1 -1
- data/examples/purplegw_example.rb +4 -3
- data/ext/account.c +6 -7
- data/ext/purple_ruby.c +107 -51
- metadata +1 -1
data/README.txt
CHANGED
@@ -1,17 +1,26 @@
|
|
1
1
|
== OVERVIEW
|
2
2
|
|
3
|
-
purple_ruby is a ruby gem to write servers that send and recive IM messages. It uses libpurple (http://developer.pidgin.im/wiki/WhatIsLibpurple) and therforce supports all protocols that Pidgin/Adium supports (MSN/Gtalk/Yahoo/AIM/ICQ etc).
|
3
|
+
purple_ruby is a ruby gem to write servers that send and recive IM messages. It uses libpurple ( http://developer.pidgin.im/wiki/WhatIsLibpurple ) and therforce supports all protocols that Pidgin/Adium supports (MSN/Gtalk/Yahoo/AIM/ICQ etc).
|
4
|
+
|
5
|
+
For MSN, we recommend msn-pecan ( http://code.google.com/p/msn-pecan/ ), which is more more stable than official MSN plugin.
|
4
6
|
|
5
7
|
Please check examples/purplegw_example.rb for details. Bascially you just tell it what to do when an IM was received, and there is an embedded tcp 'proxy' which allows you send IM messages.
|
6
8
|
|
7
|
-
Why not "ruburple"? I have used ruburple (http://rubyforge.org/projects/ruburple), but found it blocks a lot. libpurple needs to run its own event loop which interferes with ruby's green thread model. Ruburple's author has done lots of hard work to workaround the problem (http://rubyforge.org/pipermail/ruburple-development/2007-June/000005.html), but it does not work well.
|
9
|
+
Why not "ruburple"? I have used ruburple ( http://rubyforge.org/projects/ruburple ), but found it blocks a lot. libpurple needs to run its own event loop which interferes with ruby's green thread model. Ruburple's author has done lots of hard work to workaround the problem ( http://rubyforge.org/pipermail/ruburple-development/2007-June/000005.html ), but it does not work well.
|
8
10
|
|
9
11
|
== INSTALLATION
|
10
12
|
|
11
|
-
|
13
|
+
Ubuntu:
|
12
14
|
---------------
|
13
|
-
apt-get install libpurple0 libpurple-dev
|
14
|
-
gem
|
15
|
+
sudo apt-get install libpurple0 libpurple-dev
|
16
|
+
gem sources -a http://gems.github.com (you only have to do this once)
|
17
|
+
sudo gem install yong-purple_ruby
|
18
|
+
|
19
|
+
Redhat/Centos
|
20
|
+
---------------
|
21
|
+
Follow instructions here: http://www.pidgin.im/download/centos_rhel/
|
22
|
+
gem sources -a http://gems.github.com (you only have to do this once)
|
23
|
+
sudo gem install yong-purple_ruby
|
15
24
|
|
16
25
|
OSX:
|
17
26
|
----
|
@@ -20,9 +29,9 @@ sudo port install gnutls
|
|
20
29
|
(wait forever....)
|
21
30
|
sudo port install nss
|
22
31
|
(wait forever....)
|
23
|
-
wget http://downloads.sourceforge.net/pidgin/pidgin-2.5.
|
24
|
-
tar xvjf pidgin-2.5.
|
25
|
-
cd pidgin-2.5.
|
32
|
+
wget http://downloads.sourceforge.net/pidgin/pidgin-2.5.7.tar.bz2
|
33
|
+
tar xvjf pidgin-2.5.7.tar.bz2
|
34
|
+
cd pidgin-2.5.7
|
26
35
|
./configure --disable-gtkui --disable-screensaver --disable-consoleui --disable-sm --disable-perl --disable-tk --disable-tcl --disable-gstreamer --disable-schemas-install --disable-gestures --disable-cap --disable-gevolution --disable-gtkspell --disable-startup-notification --disable-avahi --disable-nm --disable-dbus --disable-meanwhile
|
27
36
|
make
|
28
37
|
(wait forever...)
|
@@ -31,8 +40,13 @@ sudo make install
|
|
31
40
|
edit your ~/.bash_profile and add this line
|
32
41
|
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
|
33
42
|
|
43
|
+
gem sources -a http://gems.github.com (you only have to do this once)
|
34
44
|
sudo gem install yong-purple_ruby
|
35
45
|
|
46
|
+
== Copyright
|
47
|
+
|
48
|
+
purple_ruby is Copyright (c) 2009 Xue Yong Zhi and Intridea, Inc., released under the GPL License.
|
49
|
+
|
36
50
|
|
37
51
|
|
38
52
|
|
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ require File.expand_path(File.join(File.dirname(__FILE__), '../ext/purple_ruby')
|
|
16
16
|
|
17
17
|
class PurpleGWExample
|
18
18
|
SERVER_IP = "127.0.0.1"
|
19
|
-
SERVER_PORT =
|
19
|
+
SERVER_PORT = 9877
|
20
20
|
|
21
21
|
def start configs
|
22
22
|
PurpleRuby.init false #use 'true' if you want to see the debug messages
|
@@ -25,15 +25,16 @@ class PurpleGWExample
|
|
25
25
|
|
26
26
|
accounts = {}
|
27
27
|
configs.each {|config|
|
28
|
+
puts "logging in #{config[:username]} (#{config[:protocol]})..."
|
28
29
|
account = PurpleRuby.login(config[:protocol], config[:username], config[:password])
|
29
30
|
accounts[config[:protocol]] = account
|
30
31
|
}
|
31
32
|
|
32
33
|
#handle incoming im messages
|
33
|
-
PurpleRuby.watch_incoming_im do |
|
34
|
+
PurpleRuby.watch_incoming_im do |acc, sender, message|
|
34
35
|
sender = sender[0...sender.index('/')] if sender.index('/') #discard anything after '/'
|
35
36
|
text = (Hpricot(message)).to_plain_text
|
36
|
-
puts "recv: #{
|
37
|
+
puts "recv: #{acc.username}, #{sender}, #{text}"
|
37
38
|
end
|
38
39
|
|
39
40
|
PurpleRuby.watch_signed_on_event do |acc|
|
data/ext/account.c
CHANGED
@@ -49,6 +49,8 @@ extern ID CALL;
|
|
49
49
|
extern VALUE cAccount;
|
50
50
|
extern VALUE new_buddy_handler;
|
51
51
|
|
52
|
+
extern VALUE check_callback(VALUE, const char*);
|
53
|
+
|
52
54
|
static char *
|
53
55
|
make_info(PurpleAccount *account, PurpleConnection *gc, const char *remote_user,
|
54
56
|
const char *id, const char *alias, const char *msg)
|
@@ -93,11 +95,12 @@ request_add(PurpleAccount *account, const char *remote_user,
|
|
93
95
|
const char *message)
|
94
96
|
{
|
95
97
|
if (new_buddy_handler != Qnil) {
|
96
|
-
VALUE
|
98
|
+
VALUE args[3];
|
97
99
|
args[0] = Data_Wrap_Struct(cAccount, NULL, NULL, account);
|
98
100
|
args[1] = rb_str_new2(NULL == remote_user ? "" : remote_user);
|
99
101
|
args[2] = rb_str_new2(NULL == message ? "" : message);
|
100
|
-
|
102
|
+
check_callback(new_buddy_handler, "new_buddy_handler");
|
103
|
+
VALUE v = rb_funcall2(new_buddy_handler, CALL, 3, args);
|
101
104
|
|
102
105
|
if (v != Qnil && v != Qfalse) {
|
103
106
|
PurpleConnection *gc = purple_account_get_connection(account);
|
@@ -107,8 +110,6 @@ request_add(PurpleAccount *account, const char *remote_user,
|
|
107
110
|
NULL, alias);
|
108
111
|
}
|
109
112
|
}
|
110
|
-
|
111
|
-
g_free(args);
|
112
113
|
}
|
113
114
|
}
|
114
115
|
|
@@ -123,7 +124,7 @@ static void *request_authorize(PurpleAccount *account,
|
|
123
124
|
void *user_data)
|
124
125
|
{
|
125
126
|
if (new_buddy_handler != Qnil) {
|
126
|
-
VALUE
|
127
|
+
VALUE args[3];
|
127
128
|
args[0] = Data_Wrap_Struct(cAccount, NULL, NULL, account);
|
128
129
|
args[1] = rb_str_new2(NULL == remote_user ? "" : remote_user);
|
129
130
|
args[2] = rb_str_new2(NULL == message ? "" : message);
|
@@ -135,8 +136,6 @@ static void *request_authorize(PurpleAccount *account,
|
|
135
136
|
} else {
|
136
137
|
deny_cb(user_data);
|
137
138
|
}
|
138
|
-
|
139
|
-
g_free(args);
|
140
139
|
}
|
141
140
|
|
142
141
|
return NULL;
|
data/ext/purple_ruby.c
CHANGED
@@ -123,16 +123,18 @@ static VALUE cPurpleRuby;
|
|
123
123
|
VALUE cAccount;
|
124
124
|
const char* UI_ID = "purplegw";
|
125
125
|
static GMainLoop *main_loop = NULL;
|
126
|
+
static GHashTable* data_hash_table = NULL;
|
127
|
+
static GHashTable* fd_hash_table = NULL;
|
128
|
+
ID CALL;
|
129
|
+
extern PurpleAccountUiOps account_ops;
|
130
|
+
|
126
131
|
static VALUE im_handler = Qnil;
|
127
132
|
static VALUE signed_on_handler = Qnil;
|
128
133
|
static VALUE connection_error_handler = Qnil;
|
129
134
|
static VALUE notify_message_handler = Qnil;
|
130
135
|
static VALUE request_handler = Qnil;
|
136
|
+
static VALUE ipc_handler = Qnil;
|
131
137
|
VALUE new_buddy_handler = Qnil;
|
132
|
-
static GHashTable* data_hash_table = NULL;
|
133
|
-
static GHashTable* fd_hash_table = NULL;
|
134
|
-
ID CALL;
|
135
|
-
extern PurpleAccountUiOps account_ops;
|
136
138
|
|
137
139
|
extern void
|
138
140
|
finch_connection_report_disconnect(PurpleConnection *gc, PurpleConnectionError reason,
|
@@ -140,42 +142,100 @@ finch_connection_report_disconnect(PurpleConnection *gc, PurpleConnectionError r
|
|
140
142
|
|
141
143
|
extern void finch_connections_init();
|
142
144
|
|
145
|
+
VALUE inspect_rb_obj(VALUE obj)
|
146
|
+
{
|
147
|
+
return rb_funcall(obj, rb_intern("inspect"), 0, 0);
|
148
|
+
}
|
149
|
+
|
150
|
+
void set_callback(VALUE* handler, const char* handler_name)
|
151
|
+
{
|
152
|
+
if (!rb_block_given_p()) {
|
153
|
+
rb_raise(rb_eArgError, "%s: no block", handler_name);
|
154
|
+
}
|
155
|
+
|
156
|
+
if (Qnil != *handler) {
|
157
|
+
rb_raise(rb_eArgError, "%s should only be assigned once", handler_name);
|
158
|
+
}
|
159
|
+
|
160
|
+
*handler = rb_block_proc();
|
161
|
+
/*
|
162
|
+
* If you create a Ruby object from C and store it in a C global variable without
|
163
|
+
* exporting it to Ruby, you must at least tell the garbage collector about it,
|
164
|
+
* lest ye be reaped inadvertently:
|
165
|
+
*/
|
166
|
+
rb_global_variable(handler);
|
167
|
+
|
168
|
+
if (rb_obj_class(*handler) != rb_cProc) {
|
169
|
+
rb_raise(rb_eTypeError, "%s got unexpected value: %s", handler_name,
|
170
|
+
RSTRING(inspect_rb_obj(*handler))->ptr);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
void check_callback(VALUE handler, const char* handler_name){
|
175
|
+
if (rb_obj_class(handler) != rb_cProc) {
|
176
|
+
rb_raise(rb_eTypeError, "%s has unexpected value: %s",
|
177
|
+
handler_name,
|
178
|
+
RSTRING(inspect_rb_obj(handler))->ptr);
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
143
182
|
void report_disconnect(PurpleConnection *gc, PurpleConnectionError reason, const char *text)
|
144
183
|
{
|
145
184
|
if (Qnil != connection_error_handler) {
|
146
|
-
VALUE
|
185
|
+
VALUE args[3];
|
147
186
|
args[0] = Data_Wrap_Struct(cAccount, NULL, NULL, purple_connection_get_account(gc));
|
148
187
|
args[1] = INT2FIX(reason);
|
149
188
|
args[2] = rb_str_new2(text);
|
150
|
-
|
189
|
+
check_callback(connection_error_handler, "connection_error_handler");
|
190
|
+
VALUE v = rb_funcall2(connection_error_handler, CALL, 3, args);
|
151
191
|
|
152
192
|
if (v != Qnil && v != Qfalse) {
|
153
193
|
finch_connection_report_disconnect(gc, reason, text);
|
154
194
|
}
|
155
|
-
|
156
|
-
g_free(args);
|
157
195
|
}
|
158
196
|
}
|
159
197
|
|
198
|
+
static void* notify_message(PurpleNotifyMsgType type,
|
199
|
+
const char *title,
|
200
|
+
const char *primary,
|
201
|
+
const char *secondary)
|
202
|
+
{
|
203
|
+
if (notify_message_handler != Qnil) {
|
204
|
+
VALUE args[4];
|
205
|
+
args[0] = INT2FIX(type);
|
206
|
+
args[1] = rb_str_new2(NULL == title ? "" : title);
|
207
|
+
args[2] = rb_str_new2(NULL == primary ? "" : primary);
|
208
|
+
args[3] = rb_str_new2(NULL == secondary ? "" : secondary);
|
209
|
+
check_callback(notify_message_handler, "notify_message_handler");
|
210
|
+
rb_funcall2(notify_message_handler, CALL, 4, args);
|
211
|
+
}
|
212
|
+
|
213
|
+
return NULL;
|
214
|
+
}
|
215
|
+
|
160
216
|
static void write_conv(PurpleConversation *conv, const char *who, const char *alias,
|
161
217
|
const char *message, PurpleMessageFlags flags, time_t mtime)
|
162
218
|
{
|
163
219
|
if (im_handler != Qnil) {
|
164
220
|
PurpleAccount* account = purple_conversation_get_account(conv);
|
165
221
|
if (strcmp(purple_account_get_protocol_id(account), "prpl-msn") == 0 &&
|
166
|
-
|
222
|
+
(strstr(message, "Message could not be sent") != NULL ||
|
223
|
+
strstr(message, "Message was not sent") != NULL ||
|
224
|
+
strstr(message, "Message may have not been sent") != NULL
|
225
|
+
)
|
226
|
+
) {
|
167
227
|
/* I have seen error like 'msn: Connection error from Switchboard server'.
|
168
228
|
* In that case, libpurple will notify user with two regular im message.
|
169
229
|
* The first message is an error message, the second one is the original message that failed to send.
|
170
230
|
*/
|
171
|
-
|
231
|
+
notify_message(PURPLE_CONNECTION_ERROR_NETWORK_ERROR, message, purple_account_get_protocol_id(account), who);
|
172
232
|
} else {
|
173
|
-
VALUE
|
174
|
-
args[0] =
|
233
|
+
VALUE args[3];
|
234
|
+
args[0] = Data_Wrap_Struct(cAccount, NULL, NULL, account);
|
175
235
|
args[1] = rb_str_new2(who);
|
176
236
|
args[2] = rb_str_new2(message);
|
237
|
+
check_callback(im_handler, "im_handler");
|
177
238
|
rb_funcall2(im_handler, CALL, 3, args);
|
178
|
-
g_free(args);
|
179
239
|
}
|
180
240
|
}
|
181
241
|
}
|
@@ -218,24 +278,6 @@ static PurpleConnectionUiOps connection_ops =
|
|
218
278
|
NULL
|
219
279
|
};
|
220
280
|
|
221
|
-
static void* notify_message(PurpleNotifyMsgType type,
|
222
|
-
const char *title,
|
223
|
-
const char *primary,
|
224
|
-
const char *secondary)
|
225
|
-
{
|
226
|
-
if (notify_message_handler != Qnil) {
|
227
|
-
VALUE *args = g_new(VALUE, 4);
|
228
|
-
args[0] = INT2FIX(type);
|
229
|
-
args[1] = rb_str_new2(NULL == title ? "" : title);
|
230
|
-
args[2] = rb_str_new2(NULL == primary ? "" : primary);
|
231
|
-
args[3] = rb_str_new2(NULL == secondary ? "" : secondary);
|
232
|
-
rb_funcall2(notify_message_handler, CALL, 4, args);
|
233
|
-
g_free(args);
|
234
|
-
}
|
235
|
-
|
236
|
-
return NULL;
|
237
|
-
}
|
238
|
-
|
239
281
|
static void* request_action(const char *title, const char *primary, const char *secondary,
|
240
282
|
int default_action,
|
241
283
|
PurpleAccount *account,
|
@@ -246,11 +288,12 @@ static void* request_action(const char *title, const char *primary, const char *
|
|
246
288
|
va_list actions)
|
247
289
|
{
|
248
290
|
if (request_handler != Qnil) {
|
249
|
-
VALUE
|
291
|
+
VALUE args[4];
|
250
292
|
args[0] = rb_str_new2(NULL == title ? "" : title);
|
251
293
|
args[1] = rb_str_new2(NULL == primary ? "" : primary);
|
252
294
|
args[2] = rb_str_new2(NULL == secondary ? "" : secondary);
|
253
295
|
args[3] = rb_str_new2(NULL == who ? "" : who);
|
296
|
+
check_callback(request_handler, "request_handler");
|
254
297
|
VALUE v = rb_funcall2(request_handler, CALL, 4, args);
|
255
298
|
|
256
299
|
if (v != Qnil && v != Qfalse) {
|
@@ -258,8 +301,6 @@ static void* request_action(const char *title, const char *primary, const char *
|
|
258
301
|
GCallback ok_cb = va_arg(actions, GCallback);
|
259
302
|
((PurpleRequestActionCb)ok_cb)(user_data, default_action);
|
260
303
|
}
|
261
|
-
|
262
|
-
g_free(args);
|
263
304
|
}
|
264
305
|
|
265
306
|
return NULL;
|
@@ -356,42 +397,42 @@ static VALUE init(VALUE self, VALUE debug)
|
|
356
397
|
static VALUE watch_incoming_im(VALUE self)
|
357
398
|
{
|
358
399
|
purple_conversations_set_ui_ops(&conv_uiops);
|
359
|
-
im_handler
|
400
|
+
set_callback(&im_handler, "im_handler");
|
360
401
|
return im_handler;
|
361
402
|
}
|
362
403
|
|
363
404
|
static VALUE watch_notify_message(VALUE self)
|
364
405
|
{
|
365
406
|
purple_notify_set_ui_ops(¬ify_ops);
|
366
|
-
notify_message_handler
|
407
|
+
set_callback(¬ify_message_handler, "notify_message_handler");
|
367
408
|
return notify_message_handler;
|
368
409
|
}
|
369
410
|
|
370
411
|
static VALUE watch_request(VALUE self)
|
371
412
|
{
|
372
413
|
purple_request_set_ui_ops(&request_ops);
|
373
|
-
request_handler
|
414
|
+
set_callback(&request_handler, "request_handler");
|
374
415
|
return request_handler;
|
375
416
|
}
|
376
417
|
|
377
418
|
static VALUE watch_new_buddy(VALUE self)
|
378
419
|
{
|
379
420
|
purple_accounts_set_ui_ops(&account_ops);
|
380
|
-
new_buddy_handler
|
421
|
+
set_callback(&new_buddy_handler, "new_buddy_handler");
|
381
422
|
return new_buddy_handler;
|
382
423
|
}
|
383
424
|
|
384
425
|
static void signed_on(PurpleConnection* connection)
|
385
426
|
{
|
386
|
-
VALUE
|
427
|
+
VALUE args[1];
|
387
428
|
args[0] = Data_Wrap_Struct(cAccount, NULL, NULL, purple_connection_get_account(connection));
|
388
|
-
|
389
|
-
|
429
|
+
check_callback(signed_on_handler, "signed_on_handler");
|
430
|
+
rb_funcall2(signed_on_handler, CALL, 1, args);
|
390
431
|
}
|
391
432
|
|
392
433
|
static VALUE watch_signed_on_event(VALUE self)
|
393
434
|
{
|
394
|
-
signed_on_handler
|
435
|
+
set_callback(&signed_on_handler, "signed_on_handler");
|
395
436
|
int handle;
|
396
437
|
purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle,
|
397
438
|
PURPLE_CALLBACK(signed_on), NULL);
|
@@ -403,14 +444,15 @@ static VALUE watch_connection_error(VALUE self)
|
|
403
444
|
finch_connections_init();
|
404
445
|
purple_connections_set_ui_ops(&connection_ops);
|
405
446
|
|
406
|
-
connection_error_handler
|
447
|
+
set_callback(&connection_error_handler, "connection_error_handler");
|
448
|
+
|
407
449
|
/*int handle;
|
408
450
|
purple_signal_connect(purple_connections_get_handle(), "connection-error", &handle,
|
409
451
|
PURPLE_CALLBACK(connection_error), NULL);*/
|
410
452
|
return connection_error_handler;
|
411
453
|
}
|
412
454
|
|
413
|
-
static void _read_socket_handler(gpointer
|
455
|
+
static void _read_socket_handler(gpointer notused, int socket, PurpleInputCondition condition)
|
414
456
|
{
|
415
457
|
char message[4096] = {0};
|
416
458
|
int i = recv(socket, message, sizeof(message) - 1, 0);
|
@@ -440,14 +482,14 @@ static void _read_socket_handler(gpointer data, int socket, PurpleInputCondition
|
|
440
482
|
purple_input_remove((guint)purple_fd);
|
441
483
|
close(socket);
|
442
484
|
|
443
|
-
VALUE
|
485
|
+
VALUE args[1];
|
444
486
|
args[0] = (VALUE)str;
|
445
|
-
|
446
|
-
|
487
|
+
check_callback(ipc_handler, "ipc_handler");
|
488
|
+
rb_funcall2(ipc_handler, CALL, 1, args);
|
447
489
|
}
|
448
490
|
}
|
449
491
|
|
450
|
-
static void _accept_socket_handler(gpointer
|
492
|
+
static void _accept_socket_handler(gpointer notused, int server_socket, PurpleInputCondition condition)
|
451
493
|
{
|
452
494
|
/* Check that it is a read condition */
|
453
495
|
if (condition != PURPLE_INPUT_READ)
|
@@ -469,7 +511,7 @@ static void _accept_socket_handler(gpointer data, int server_socket, PurpleInput
|
|
469
511
|
|
470
512
|
purple_debug_info("purple_ruby", "new connection: %d\n", client_socket);
|
471
513
|
|
472
|
-
guint purple_fd = purple_input_add(client_socket, PURPLE_INPUT_READ, _read_socket_handler,
|
514
|
+
guint purple_fd = purple_input_add(client_socket, PURPLE_INPUT_READ, _read_socket_handler, NULL);
|
473
515
|
|
474
516
|
g_hash_table_insert(data_hash_table, (gpointer)client_socket, (gpointer)rb_str_new2(""));
|
475
517
|
g_hash_table_insert(fd_hash_table, (gpointer)client_socket, (gpointer)purple_fd);
|
@@ -504,10 +546,10 @@ static VALUE watch_incoming_ipc(VALUE self, VALUE serverip, VALUE port)
|
|
504
546
|
return Qnil;
|
505
547
|
}
|
506
548
|
|
507
|
-
|
549
|
+
set_callback(&ipc_handler, "ipc_handler");
|
508
550
|
|
509
551
|
/* Open a watcher in the socket we have just opened */
|
510
|
-
purple_input_add(soc, PURPLE_INPUT_READ, _accept_socket_handler,
|
552
|
+
purple_input_add(soc, PURPLE_INPUT_READ, _accept_socket_handler, NULL);
|
511
553
|
|
512
554
|
return port;
|
513
555
|
}
|
@@ -530,6 +572,20 @@ static VALUE main_loop_run(VALUE self)
|
|
530
572
|
{
|
531
573
|
main_loop = g_main_loop_new(NULL, FALSE);
|
532
574
|
g_main_loop_run(main_loop);
|
575
|
+
|
576
|
+
#ifdef DEBUG_MEM_LEAK
|
577
|
+
printf("QUIT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
|
578
|
+
purple_core_quit();
|
579
|
+
if (im_handler == Qnil) rb_gc_unregister_address(&im_handler);
|
580
|
+
if (signed_on_handler == Qnil) rb_gc_unregister_address(&signed_on_handler);
|
581
|
+
if (connection_error_handler == Qnil) rb_gc_unregister_address(&connection_error_handler);
|
582
|
+
if (notify_message_handler == Qnil) rb_gc_unregister_address(¬ify_message_handler);
|
583
|
+
if (request_handler == Qnil) rb_gc_unregister_address(&request_handler);
|
584
|
+
if (ipc_handler == Qnil) rb_gc_unregister_address(&ipc_handler);
|
585
|
+
if (new_buddy_handler == Qnil) rb_gc_unregister_address(&new_buddy_handler);
|
586
|
+
rb_gc_start();
|
587
|
+
#endif
|
588
|
+
|
533
589
|
return Qnil;
|
534
590
|
}
|
535
591
|
|