3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include <libsoup/soup.h>
26 #include "glibcompat.h"
36 PurpleRoomlist
*roomlist
;
46 * Represents the connection data used by #FacebookProtocol.
70 * Represents the data used for fetching images.
75 FbDataImagePrivate
*priv
;
78 static const gchar
*fb_props_strs
[] = {
85 G_DEFINE_TYPE_WITH_PRIVATE(FbData
, fb_data
, G_TYPE_OBJECT
);
86 G_DEFINE_TYPE_WITH_PRIVATE(FbDataImage
, fb_data_image
, G_TYPE_OBJECT
);
89 fb_data_dispose(GObject
*obj
)
91 FbDataPrivate
*priv
= FB_DATA(obj
)->priv
;
95 soup_session_abort(priv
->cons
);
96 g_hash_table_iter_init(&iter
, priv
->evs
);
98 while (g_hash_table_iter_next(&iter
, NULL
, &ptr
)) {
99 g_source_remove(GPOINTER_TO_UINT(ptr
));
102 if (G_LIKELY(priv
->api
!= NULL
)) {
103 g_object_unref(priv
->api
);
106 g_object_unref(priv
->cons
);
107 g_queue_free_full(priv
->msgs
, (GDestroyNotify
) fb_api_message_free
);
109 g_hash_table_destroy(priv
->imgs
);
110 g_hash_table_destroy(priv
->unread
);
111 g_hash_table_destroy(priv
->evs
);
115 fb_data_class_init(FbDataClass
*klass
)
117 GObjectClass
*gklass
= G_OBJECT_CLASS(klass
);
119 gklass
->dispose
= fb_data_dispose
;
123 fb_data_init(FbData
*fata
)
125 FbDataPrivate
*priv
= fb_data_get_instance_private(fata
);
128 priv
->msgs
= g_queue_new();
130 priv
->imgs
= g_hash_table_new_full(g_direct_hash
, g_direct_equal
,
131 g_object_unref
, NULL
);
132 priv
->unread
= g_hash_table_new_full(fb_id_hash
, fb_id_equal
,
134 priv
->evs
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
139 fb_data_image_dispose(GObject
*obj
)
141 FbDataImage
*img
= FB_DATA_IMAGE(obj
);
142 FbDataImagePrivate
*priv
= img
->priv
;
143 FbData
*fata
= priv
->fata
;
145 if ((priv
->dunc
!= NULL
) && (priv
->data
!= NULL
)) {
146 priv
->dunc(priv
->data
);
150 g_hash_table_steal(fata
->priv
->imgs
, img
);
154 fb_data_image_class_init(FbDataImageClass
*klass
)
156 GObjectClass
*gklass
= G_OBJECT_CLASS(klass
);
158 gklass
->dispose
= fb_data_image_dispose
;
162 fb_data_image_init(FbDataImage
*img
)
164 FbDataImagePrivate
*priv
= fb_data_image_get_instance_private(img
);
169 fb_data_new(PurpleConnection
*gc
, GProxyResolver
*resolver
)
174 fata
= g_object_new(FB_TYPE_DATA
, NULL
);
177 priv
->cons
= soup_session_new_with_options(SOUP_SESSION_PROXY_RESOLVER
,
179 priv
->api
= fb_api_new(gc
, resolver
);
186 fb_data_load(FbData
*fata
)
194 GValue val
= G_VALUE_INIT
;
197 g_return_val_if_fail(FB_IS_DATA(fata
), FALSE
);
199 acct
= purple_connection_get_account(priv
->gc
);
201 for (i
= 0; i
< G_N_ELEMENTS(fb_props_strs
); i
++) {
202 str
= purple_account_get_string(acct
, fb_props_strs
[i
], NULL
);
208 g_value_init(&val
, G_TYPE_STRING
);
209 g_value_set_string(&val
, str
);
210 g_object_set_property(G_OBJECT(priv
->api
), fb_props_strs
[i
],
215 str
= purple_account_get_string(acct
, "mid", NULL
);
218 uint
= g_ascii_strtoull(str
, NULL
, 10);
219 g_value_init(&val
, G_TYPE_UINT64
);
220 g_value_set_uint64(&val
, uint
);
221 g_object_set_property(G_OBJECT(priv
->api
), "mid", &val
);
227 str
= purple_account_get_string(acct
, "uid", NULL
);
230 id
= FB_ID_FROM_STR(str
);
231 g_value_init(&val
, FB_TYPE_ID
);
232 g_value_set_int64(&val
, id
);
233 g_object_set_property(G_OBJECT(priv
->api
), "uid", &val
);
239 fb_api_rehash(priv
->api
);
244 fb_data_save(FbData
*fata
)
251 GValue val
= G_VALUE_INIT
;
254 g_return_if_fail(FB_IS_DATA(fata
));
256 acct
= purple_connection_get_account(priv
->gc
);
258 for (i
= 0; i
< G_N_ELEMENTS(fb_props_strs
); i
++) {
259 g_value_init(&val
, G_TYPE_STRING
);
260 g_object_get_property(G_OBJECT(priv
->api
), fb_props_strs
[i
],
262 str
= g_value_get_string(&val
);
264 if (purple_strequal(fb_props_strs
[i
], "token") && !purple_account_get_remember_password(acct
)) {
267 purple_account_set_string(acct
, fb_props_strs
[i
], str
);
271 g_value_init(&val
, G_TYPE_UINT64
);
272 g_object_get_property(G_OBJECT(priv
->api
), "mid", &val
);
273 uint
= g_value_get_uint64(&val
);
276 dup
= g_strdup_printf("%" G_GINT64_FORMAT
, uint
);
277 purple_account_set_string(acct
, "mid", dup
);
280 g_value_init(&val
, G_TYPE_INT64
);
281 g_object_get_property(G_OBJECT(priv
->api
), "uid", &val
);
282 uint
= g_value_get_int64(&val
);
285 dup
= g_strdup_printf("%" FB_ID_FORMAT
, uint
);
286 purple_account_set_string(acct
, "uid", dup
);
291 fb_data_add_timeout(FbData
*fata
, const gchar
*name
, guint interval
,
292 GSourceFunc func
, gpointer data
)
298 g_return_if_fail(FB_IS_DATA(fata
));
301 fb_data_clear_timeout(fata
, name
, TRUE
);
303 key
= g_strdup(name
);
304 id
= g_timeout_add(interval
, func
, data
);
305 g_hash_table_replace(priv
->evs
, key
, GUINT_TO_POINTER(id
));
309 fb_data_clear_timeout(FbData
*fata
, const gchar
*name
, gboolean remove
)
315 g_return_if_fail(FB_IS_DATA(fata
));
318 ptr
= g_hash_table_lookup(priv
->evs
, name
);
319 id
= GPOINTER_TO_UINT(ptr
);
321 if ((id
> 0) && remove
) {
325 g_hash_table_remove(priv
->evs
, name
);
329 fb_data_get_api(FbData
*fata
)
333 g_return_val_if_fail(FB_IS_DATA(fata
), NULL
);
340 fb_data_get_connection(FbData
*fata
)
344 g_return_val_if_fail(FB_IS_DATA(fata
), NULL
);
351 fb_data_get_roomlist(FbData
*fata
)
355 g_return_val_if_fail(FB_IS_DATA(fata
), NULL
);
358 return priv
->roomlist
;
362 fb_data_get_unread(FbData
*fata
, FbId id
)
367 g_return_val_if_fail(FB_IS_DATA(fata
), FALSE
);
368 g_return_val_if_fail(id
!= 0, FALSE
);
371 ptr
= g_hash_table_lookup(priv
->unread
, &id
);
372 return GPOINTER_TO_INT(ptr
);
376 fb_data_set_roomlist(FbData
*fata
, PurpleRoomlist
*list
)
380 g_return_if_fail(FB_IS_DATA(fata
));
383 priv
->roomlist
= list
;
387 fb_data_set_unread(FbData
*fata
, FbId id
, gboolean unread
)
392 g_return_if_fail(FB_IS_DATA(fata
));
393 g_return_if_fail(id
!= 0);
397 g_hash_table_remove(priv
->unread
, &id
);
401 key
= g_memdup(&id
, sizeof id
);
402 g_hash_table_replace(priv
->unread
, key
, GINT_TO_POINTER(unread
));
406 fb_data_add_message(FbData
*fata
, FbApiMessage
*msg
)
410 g_return_if_fail(FB_IS_DATA(fata
));
413 g_queue_push_tail(priv
->msgs
, msg
);
417 fb_data_remove_message(FbData
*fata
, FbApiMessage
*msg
)
421 g_return_if_fail(FB_IS_DATA(fata
));
424 g_queue_remove(priv
->msgs
, msg
);
428 fb_data_take_messages(FbData
*fata
, FbId uid
)
436 g_return_val_if_fail(FB_IS_DATA(fata
), NULL
);
438 l
= priv
->msgs
->tail
;
444 if (msg
->uid
== uid
) {
445 msgs
= g_slist_prepend(msgs
, msg
);
446 g_queue_delete_link(priv
->msgs
, l
);
456 fb_data_image_add(FbData
*fata
, const gchar
*url
, FbDataImageFunc func
,
457 gpointer data
, GDestroyNotify dunc
)
460 FbDataImagePrivate
*priv
;
462 g_return_val_if_fail(FB_IS_DATA(fata
), NULL
);
463 g_return_val_if_fail(url
!= NULL
, NULL
);
464 g_return_val_if_fail(func
!= NULL
, NULL
);
466 img
= g_object_new(FB_TYPE_DATA_IMAGE
, NULL
);
470 priv
->url
= g_strdup(url
);
475 g_hash_table_insert(fata
->priv
->imgs
, img
, img
);
480 fb_data_image_get_active(FbDataImage
*img
)
482 FbDataImagePrivate
*priv
;
484 g_return_val_if_fail(FB_IS_DATA_IMAGE(img
), FALSE
);
491 fb_data_image_get_data(FbDataImage
*img
)
493 FbDataImagePrivate
*priv
;
495 g_return_val_if_fail(FB_IS_DATA_IMAGE(img
), NULL
);
502 fb_data_image_get_fata(FbDataImage
*img
)
504 FbDataImagePrivate
*priv
;
506 g_return_val_if_fail(FB_IS_DATA_IMAGE(img
), NULL
);
513 fb_data_image_get_image(FbDataImage
*img
, gsize
*size
)
515 FbDataImagePrivate
*priv
;
517 g_return_val_if_fail(FB_IS_DATA_IMAGE(img
), NULL
);
528 fb_data_image_dup_image(FbDataImage
*img
, gsize
*size
)
530 FbDataImagePrivate
*priv
;
532 g_return_val_if_fail(FB_IS_DATA_IMAGE(img
), NULL
);
539 if (priv
->size
< 1) {
543 return g_memdup(priv
->image
, priv
->size
);
547 fb_data_image_get_url(FbDataImage
*img
)
549 FbDataImagePrivate
*priv
;
551 g_return_val_if_fail(FB_IS_DATA_IMAGE(img
), NULL
);
558 fb_data_image_cb(G_GNUC_UNUSED SoupSession
*session
, SoupMessage
*res
,
561 FbDataImage
*img
= data
;
562 FbDataImagePrivate
*priv
= img
->priv
;
565 fb_http_error_chk(res
, &err
);
567 priv
->image
= (guint8
*)res
->response_body
->data
;
568 priv
->size
= res
->response_body
->length
;
569 priv
->func(img
, err
);
571 if (G_LIKELY(err
== NULL
)) {
572 fb_data_image_queue(priv
->fata
);
581 fb_data_image_queue(FbData
*fata
)
589 g_return_if_fail(FB_IS_DATA(fata
));
591 g_hash_table_iter_init(&iter
, priv
->imgs
);
593 while (g_hash_table_iter_next(&iter
, (gpointer
*) &img
, NULL
)) {
594 if (fb_data_image_get_active(img
)) {
599 if (active
>= FB_DATA_ICON_MAX
) {
603 g_hash_table_iter_init(&iter
, priv
->imgs
);
605 while (g_hash_table_iter_next(&iter
, (gpointer
*) &img
, NULL
)) {
608 if (fb_data_image_get_active(img
)) {
612 img
->priv
->active
= TRUE
;
613 url
= fb_data_image_get_url(img
);
615 msg
= soup_message_new("GET", url
);
616 // purple_http_request_set_max_len(req, FB_DATA_ICON_SIZE_MAX);
617 soup_session_queue_message(priv
->cons
, msg
, fb_data_image_cb
, img
);
619 if (++active
>= FB_DATA_ICON_MAX
) {