mark PurpleImageClass as private
[pidgin-git.git] / libpurple / protocols / facebook / data.c
blob8c7bd7ac1352bd82e0fb8a5e8ea4134fa19f197e
1 /* purple
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
5 * source distribution.
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 <string.h>
24 #include "account.h"
25 #include "glibcompat.h"
27 #include "api.h"
28 #include "data.h"
30 typedef struct
32 FbApi *api;
33 FbHttpConns *cons;
34 PurpleConnection *gc;
35 PurpleRoomlist *roomlist;
36 GQueue *msgs;
37 GHashTable *imgs;
38 GHashTable *unread;
39 GHashTable *evs;
40 } FbDataPrivate;
42 /**
43 * FbData:
45 * Represents the connection data used by #FacebookProtocol.
47 struct _FbData
49 GObject parent;
50 FbDataPrivate *priv;
53 typedef struct
55 FbData *fata;
56 gchar *url;
57 FbDataImageFunc func;
58 gpointer data;
59 GDestroyNotify dunc;
61 gboolean active;
62 const guint8 *image;
63 gsize size;
64 } FbDataImagePrivate;
66 /**
67 * FbDataImage:
69 * Represents the data used for fetching images.
71 struct _FbDataImage
73 GObject parent;
74 FbDataImagePrivate *priv;
77 static const gchar *fb_props_strs[] = {
78 "cid",
79 "did",
80 "stoken",
81 "token"
84 G_DEFINE_TYPE_WITH_PRIVATE(FbData, fb_data, G_TYPE_OBJECT);
85 G_DEFINE_TYPE_WITH_PRIVATE(FbDataImage, fb_data_image, G_TYPE_OBJECT);
87 static void
88 fb_data_dispose(GObject *obj)
90 FbDataPrivate *priv = FB_DATA(obj)->priv;
91 GHashTableIter iter;
92 gpointer ptr;
94 fb_http_conns_cancel_all(priv->cons);
95 g_hash_table_iter_init(&iter, priv->evs);
97 while (g_hash_table_iter_next(&iter, NULL, &ptr)) {
98 g_source_remove(GPOINTER_TO_UINT(ptr));
101 if (G_LIKELY(priv->api != NULL)) {
102 g_object_unref(priv->api);
105 fb_http_conns_free(priv->cons);
106 g_queue_free_full(priv->msgs, (GDestroyNotify) fb_api_message_free);
108 g_hash_table_destroy(priv->imgs);
109 g_hash_table_destroy(priv->unread);
110 g_hash_table_destroy(priv->evs);
113 static void
114 fb_data_class_init(FbDataClass *klass)
116 GObjectClass *gklass = G_OBJECT_CLASS(klass);
118 gklass->dispose = fb_data_dispose;
121 static void
122 fb_data_init(FbData *fata)
124 FbDataPrivate *priv = fb_data_get_instance_private(fata);
125 fata->priv = priv;
127 priv->cons = fb_http_conns_new();
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,
133 g_free, NULL);
134 priv->evs = g_hash_table_new_full(g_str_hash, g_str_equal,
135 g_free, NULL);
138 static void
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);
149 g_free(priv->url);
150 g_hash_table_steal(fata->priv->imgs, img);
153 static void
154 fb_data_image_class_init(FbDataImageClass *klass)
156 GObjectClass *gklass = G_OBJECT_CLASS(klass);
158 gklass->dispose = fb_data_image_dispose;
161 static void
162 fb_data_image_init(FbDataImage *img)
164 FbDataImagePrivate *priv = fb_data_image_get_instance_private(img);
165 img->priv = priv;
168 FbData *
169 fb_data_new(PurpleConnection *gc)
171 FbData *fata;
172 FbDataPrivate *priv;
174 fata = g_object_new(FB_TYPE_DATA, NULL);
175 priv = fata->priv;
177 priv->api = fb_api_new(gc);
178 priv->gc = gc;
180 return fata;
183 gboolean
184 fb_data_load(FbData *fata)
186 const gchar *str;
187 FbDataPrivate *priv;
188 FbId id;
189 gboolean ret = TRUE;
190 guint i;
191 guint64 uint;
192 GValue val = G_VALUE_INIT;
193 PurpleAccount *acct;
195 g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
196 priv = fata->priv;
197 acct = purple_connection_get_account(priv->gc);
199 for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
200 str = purple_account_get_string(acct, fb_props_strs[i], NULL);
202 if (str == NULL) {
203 ret = FALSE;
206 g_value_init(&val, G_TYPE_STRING);
207 g_value_set_string(&val, str);
208 g_object_set_property(G_OBJECT(priv->api), fb_props_strs[i],
209 &val);
210 g_value_unset(&val);
213 str = purple_account_get_string(acct, "mid", NULL);
215 if (str != NULL) {
216 uint = g_ascii_strtoull(str, NULL, 10);
217 g_value_init(&val, G_TYPE_UINT64);
218 g_value_set_uint64(&val, uint);
219 g_object_set_property(G_OBJECT(priv->api), "mid", &val);
220 g_value_unset(&val);
221 } else {
222 ret = FALSE;
225 str = purple_account_get_string(acct, "uid", NULL);
227 if (str != NULL) {
228 id = FB_ID_FROM_STR(str);
229 g_value_init(&val, FB_TYPE_ID);
230 g_value_set_int64(&val, id);
231 g_object_set_property(G_OBJECT(priv->api), "uid", &val);
232 g_value_unset(&val);
233 } else {
234 ret = FALSE;
237 fb_api_rehash(priv->api);
238 return ret;
241 void
242 fb_data_save(FbData *fata)
244 const gchar *str;
245 FbDataPrivate *priv;
246 gchar *dup;
247 guint i;
248 guint64 uint;
249 GValue val = G_VALUE_INIT;
250 PurpleAccount *acct;
252 g_return_if_fail(FB_IS_DATA(fata));
253 priv = fata->priv;
254 acct = purple_connection_get_account(priv->gc);
256 for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
257 g_value_init(&val, G_TYPE_STRING);
258 g_object_get_property(G_OBJECT(priv->api), fb_props_strs[i],
259 &val);
260 str = g_value_get_string(&val);
262 if (purple_strequal(fb_props_strs[i], "token") && !purple_account_get_remember_password(acct)) {
263 str = "";
265 purple_account_set_string(acct, fb_props_strs[i], str);
266 g_value_unset(&val);
269 g_value_init(&val, G_TYPE_UINT64);
270 g_object_get_property(G_OBJECT(priv->api), "mid", &val);
271 uint = g_value_get_uint64(&val);
272 g_value_unset(&val);
274 dup = g_strdup_printf("%" G_GINT64_FORMAT, uint);
275 purple_account_set_string(acct, "mid", dup);
276 g_free(dup);
278 g_value_init(&val, G_TYPE_INT64);
279 g_object_get_property(G_OBJECT(priv->api), "uid", &val);
280 uint = g_value_get_int64(&val);
281 g_value_unset(&val);
283 dup = g_strdup_printf("%" FB_ID_FORMAT, uint);
284 purple_account_set_string(acct, "uid", dup);
285 g_free(dup);
288 void
289 fb_data_add_timeout(FbData *fata, const gchar *name, guint interval,
290 GSourceFunc func, gpointer data)
292 FbDataPrivate *priv;
293 gchar *key;
294 guint id;
296 g_return_if_fail(FB_IS_DATA(fata));
297 priv = fata->priv;
299 fb_data_clear_timeout(fata, name, TRUE);
301 key = g_strdup(name);
302 id = g_timeout_add(interval, func, data);
303 g_hash_table_replace(priv->evs, key, GUINT_TO_POINTER(id));
306 void
307 fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove)
309 FbDataPrivate *priv;
310 gpointer ptr;
311 guint id;
313 g_return_if_fail(FB_IS_DATA(fata));
314 priv = fata->priv;
316 ptr = g_hash_table_lookup(priv->evs, name);
317 id = GPOINTER_TO_UINT(ptr);
319 if ((id > 0) && remove) {
320 g_source_remove(id);
323 g_hash_table_remove(priv->evs, name);
326 FbApi *
327 fb_data_get_api(FbData *fata)
329 FbDataPrivate *priv;
331 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
332 priv = fata->priv;
334 return priv->api;
337 PurpleConnection *
338 fb_data_get_connection(FbData *fata)
340 FbDataPrivate *priv;
342 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
343 priv = fata->priv;
345 return priv->gc;
348 PurpleRoomlist *
349 fb_data_get_roomlist(FbData *fata)
351 FbDataPrivate *priv;
353 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
354 priv = fata->priv;
356 return priv->roomlist;
359 gboolean
360 fb_data_get_unread(FbData *fata, FbId id)
362 FbDataPrivate *priv;
363 gpointer *ptr;
365 g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
366 g_return_val_if_fail(id != 0, FALSE);
367 priv = fata->priv;
369 ptr = g_hash_table_lookup(priv->unread, &id);
370 return GPOINTER_TO_INT(ptr);
373 void
374 fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list)
376 FbDataPrivate *priv;
378 g_return_if_fail(FB_IS_DATA(fata));
379 priv = fata->priv;
381 priv->roomlist = list;
384 void
385 fb_data_set_unread(FbData *fata, FbId id, gboolean unread)
387 FbDataPrivate *priv;
388 gpointer key;
390 g_return_if_fail(FB_IS_DATA(fata));
391 g_return_if_fail(id != 0);
392 priv = fata->priv;
394 if (!unread) {
395 g_hash_table_remove(priv->unread, &id);
396 return;
399 key = g_memdup(&id, sizeof id);
400 g_hash_table_replace(priv->unread, key, GINT_TO_POINTER(unread));
403 void
404 fb_data_add_message(FbData *fata, FbApiMessage *msg)
406 FbDataPrivate *priv;
408 g_return_if_fail(FB_IS_DATA(fata));
409 priv = fata->priv;
411 g_queue_push_tail(priv->msgs, msg);
414 void
415 fb_data_remove_message(FbData *fata, FbApiMessage *msg)
417 FbDataPrivate *priv;
419 g_return_if_fail(FB_IS_DATA(fata));
420 priv = fata->priv;
422 g_queue_remove(priv->msgs, msg);
425 GSList *
426 fb_data_take_messages(FbData *fata, FbId uid)
428 FbApiMessage *msg;
429 FbDataPrivate *priv;
430 GList *l;
431 GList *prev;
432 GSList *msgs = NULL;
434 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
435 priv = fata->priv;
436 l = priv->msgs->tail;
438 while (l != NULL) {
439 msg = l->data;
440 prev = l->prev;
442 if (msg->uid == uid) {
443 msgs = g_slist_prepend(msgs, msg);
444 g_queue_delete_link(priv->msgs, l);
447 l = prev;
450 return msgs;
453 FbDataImage *
454 fb_data_image_add(FbData *fata, const gchar *url, FbDataImageFunc func,
455 gpointer data, GDestroyNotify dunc)
457 FbDataImage *img;
458 FbDataImagePrivate *priv;
460 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
461 g_return_val_if_fail(url != NULL, NULL);
462 g_return_val_if_fail(func != NULL, NULL);
464 img = g_object_new(FB_TYPE_DATA_IMAGE, NULL);
465 priv = img->priv;
467 priv->fata = fata;
468 priv->url = g_strdup(url);
469 priv->func = func;
470 priv->data = data;
471 priv->dunc = dunc;
473 g_hash_table_insert(fata->priv->imgs, img, img);
474 return img;
477 gboolean
478 fb_data_image_get_active(FbDataImage *img)
480 FbDataImagePrivate *priv;
482 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), FALSE);
483 priv = img->priv;
485 return priv->active;
488 gpointer
489 fb_data_image_get_data(FbDataImage *img)
491 FbDataImagePrivate *priv;
493 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
494 priv = img->priv;
496 return priv->data;
499 FbData *
500 fb_data_image_get_fata(FbDataImage *img)
502 FbDataImagePrivate *priv;
504 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
505 priv = img->priv;
507 return priv->fata;
510 const guint8 *
511 fb_data_image_get_image(FbDataImage *img, gsize *size)
513 FbDataImagePrivate *priv;
515 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
516 priv = img->priv;
518 if (size != NULL) {
519 *size = priv->size;
522 return priv->image;
525 guint8 *
526 fb_data_image_dup_image(FbDataImage *img, gsize *size)
528 FbDataImagePrivate *priv;
530 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
531 priv = img->priv;
533 if (size != NULL) {
534 *size = priv->size;
537 if (priv->size < 1) {
538 return NULL;
541 return g_memdup(priv->image, priv->size);
544 const gchar *
545 fb_data_image_get_url(FbDataImage *img)
547 FbDataImagePrivate *priv;
549 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
550 priv = img->priv;
552 return priv->url;
555 static void
556 fb_data_image_cb(PurpleHttpConnection *con, PurpleHttpResponse *res,
557 gpointer data)
559 FbDataImage *img = data;
560 FbDataImagePrivate *priv = img->priv;
561 FbDataPrivate *driv = priv->fata->priv;
562 GError *err = NULL;
564 if (fb_http_conns_is_canceled(driv->cons)) {
565 return;
568 fb_http_conns_remove(driv->cons, con);
569 fb_http_error_chk(res, &err);
571 priv->image = (guint8 *) purple_http_response_get_data(res, &priv->size);
572 priv->func(img, err);
574 if (G_LIKELY(err == NULL)) {
575 fb_data_image_queue(priv->fata);
576 } else {
577 g_error_free(err);
580 g_object_unref(img);
583 void
584 fb_data_image_queue(FbData *fata)
586 const gchar *url;
587 FbDataImage *img;
588 FbDataPrivate *priv;
589 GHashTableIter iter;
590 guint active = 0;
591 PurpleHttpConnection *con;
593 g_return_if_fail(FB_IS_DATA(fata));
594 priv = fata->priv;
595 g_hash_table_iter_init(&iter, priv->imgs);
597 while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
598 if (fb_data_image_get_active(img)) {
599 active++;
603 if (active >= FB_DATA_ICON_MAX) {
604 return;
607 g_hash_table_iter_init(&iter, priv->imgs);
609 while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
610 PurpleHttpRequest *req;
612 if (fb_data_image_get_active(img)) {
613 continue;
616 img->priv->active = TRUE;
617 url = fb_data_image_get_url(img);
619 req = purple_http_request_new(url);
620 purple_http_request_set_max_len(req, FB_DATA_ICON_SIZE_MAX);
621 con = purple_http_request(priv->gc, req,
622 fb_data_image_cb, img);
623 fb_http_conns_add(priv->cons, con);
624 purple_http_request_unref(req);
626 if (++active >= FB_DATA_ICON_MAX) {
627 break;