yong-purple_ruby 0.4.1 → 0.5.3
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.
- 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
|
|