Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / facebook / data.c
blob67d2c45291dcfa1e5d127942392a190df0f3ef3c
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 <libsoup/soup.h>
23 #include <string.h>
25 #include "account.h"
26 #include "glibcompat.h"
28 #include "api.h"
29 #include "data.h"
31 typedef struct
33 FbApi *api;
34 SoupSession *cons;
35 PurpleConnection *gc;
36 PurpleRoomlist *roomlist;
37 GQueue *msgs;
38 GHashTable *imgs;
39 GHashTable *unread;
40 GHashTable *evs;
41 } FbDataPrivate;
43 /**
44 * FbData:
46 * Represents the connection data used by #FacebookProtocol.
48 struct _FbData
50 GObject parent;
51 FbDataPrivate *priv;
54 typedef struct
56 FbData *fata;
57 gchar *url;
58 FbDataImageFunc func;
59 gpointer data;
60 GDestroyNotify dunc;
62 gboolean active;
63 const guint8 *image;
64 gsize size;
65 } FbDataImagePrivate;
67 /**
68 * FbDataImage:
70 * Represents the data used for fetching images.
72 struct _FbDataImage
74 GObject parent;
75 FbDataImagePrivate *priv;
78 static const gchar *fb_props_strs[] = {
79 "cid",
80 "did",
81 "stoken",
82 "token"
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);
88 static void
89 fb_data_dispose(GObject *obj)
91 FbDataPrivate *priv = FB_DATA(obj)->priv;
92 GHashTableIter iter;
93 gpointer ptr;
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);
114 static void
115 fb_data_class_init(FbDataClass *klass)
117 GObjectClass *gklass = G_OBJECT_CLASS(klass);
119 gklass->dispose = fb_data_dispose;
122 static void
123 fb_data_init(FbData *fata)
125 FbDataPrivate *priv = fb_data_get_instance_private(fata);
126 fata->priv = priv;
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, GProxyResolver *resolver)
171 FbData *fata;
172 FbDataPrivate *priv;
174 fata = g_object_new(FB_TYPE_DATA, NULL);
175 priv = fata->priv;
177 priv->cons = soup_session_new_with_options(SOUP_SESSION_PROXY_RESOLVER,
178 resolver, NULL);
179 priv->api = fb_api_new(gc, resolver);
180 priv->gc = gc;
182 return fata;
185 gboolean
186 fb_data_load(FbData *fata)
188 const gchar *str;
189 FbDataPrivate *priv;
190 FbId id;
191 gboolean ret = TRUE;
192 guint i;
193 guint64 uint;
194 GValue val = G_VALUE_INIT;
195 PurpleAccount *acct;
197 g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
198 priv = fata->priv;
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);
204 if (str == NULL) {
205 ret = FALSE;
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],
211 &val);
212 g_value_unset(&val);
215 str = purple_account_get_string(acct, "mid", NULL);
217 if (str != 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);
222 g_value_unset(&val);
223 } else {
224 ret = FALSE;
227 str = purple_account_get_string(acct, "uid", NULL);
229 if (str != 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);
234 g_value_unset(&val);
235 } else {
236 ret = FALSE;
239 fb_api_rehash(priv->api);
240 return ret;
243 void
244 fb_data_save(FbData *fata)
246 const gchar *str;
247 FbDataPrivate *priv;
248 gchar *dup;
249 guint i;
250 guint64 uint;
251 GValue val = G_VALUE_INIT;
252 PurpleAccount *acct;
254 g_return_if_fail(FB_IS_DATA(fata));
255 priv = fata->priv;
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],
261 &val);
262 str = g_value_get_string(&val);
264 if (purple_strequal(fb_props_strs[i], "token") && !purple_account_get_remember_password(acct)) {
265 str = "";
267 purple_account_set_string(acct, fb_props_strs[i], str);
268 g_value_unset(&val);
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);
274 g_value_unset(&val);
276 dup = g_strdup_printf("%" G_GINT64_FORMAT, uint);
277 purple_account_set_string(acct, "mid", dup);
278 g_free(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);
283 g_value_unset(&val);
285 dup = g_strdup_printf("%" FB_ID_FORMAT, uint);
286 purple_account_set_string(acct, "uid", dup);
287 g_free(dup);
290 void
291 fb_data_add_timeout(FbData *fata, const gchar *name, guint interval,
292 GSourceFunc func, gpointer data)
294 FbDataPrivate *priv;
295 gchar *key;
296 guint id;
298 g_return_if_fail(FB_IS_DATA(fata));
299 priv = fata->priv;
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));
308 void
309 fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove)
311 FbDataPrivate *priv;
312 gpointer ptr;
313 guint id;
315 g_return_if_fail(FB_IS_DATA(fata));
316 priv = fata->priv;
318 ptr = g_hash_table_lookup(priv->evs, name);
319 id = GPOINTER_TO_UINT(ptr);
321 if ((id > 0) && remove) {
322 g_source_remove(id);
325 g_hash_table_remove(priv->evs, name);
328 FbApi *
329 fb_data_get_api(FbData *fata)
331 FbDataPrivate *priv;
333 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
334 priv = fata->priv;
336 return priv->api;
339 PurpleConnection *
340 fb_data_get_connection(FbData *fata)
342 FbDataPrivate *priv;
344 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
345 priv = fata->priv;
347 return priv->gc;
350 PurpleRoomlist *
351 fb_data_get_roomlist(FbData *fata)
353 FbDataPrivate *priv;
355 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
356 priv = fata->priv;
358 return priv->roomlist;
361 gboolean
362 fb_data_get_unread(FbData *fata, FbId id)
364 FbDataPrivate *priv;
365 gpointer *ptr;
367 g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
368 g_return_val_if_fail(id != 0, FALSE);
369 priv = fata->priv;
371 ptr = g_hash_table_lookup(priv->unread, &id);
372 return GPOINTER_TO_INT(ptr);
375 void
376 fb_data_set_roomlist(FbData *fata, PurpleRoomlist *list)
378 FbDataPrivate *priv;
380 g_return_if_fail(FB_IS_DATA(fata));
381 priv = fata->priv;
383 priv->roomlist = list;
386 void
387 fb_data_set_unread(FbData *fata, FbId id, gboolean unread)
389 FbDataPrivate *priv;
390 gpointer key;
392 g_return_if_fail(FB_IS_DATA(fata));
393 g_return_if_fail(id != 0);
394 priv = fata->priv;
396 if (!unread) {
397 g_hash_table_remove(priv->unread, &id);
398 return;
401 key = g_memdup(&id, sizeof id);
402 g_hash_table_replace(priv->unread, key, GINT_TO_POINTER(unread));
405 void
406 fb_data_add_message(FbData *fata, FbApiMessage *msg)
408 FbDataPrivate *priv;
410 g_return_if_fail(FB_IS_DATA(fata));
411 priv = fata->priv;
413 g_queue_push_tail(priv->msgs, msg);
416 void
417 fb_data_remove_message(FbData *fata, FbApiMessage *msg)
419 FbDataPrivate *priv;
421 g_return_if_fail(FB_IS_DATA(fata));
422 priv = fata->priv;
424 g_queue_remove(priv->msgs, msg);
427 GSList *
428 fb_data_take_messages(FbData *fata, FbId uid)
430 FbApiMessage *msg;
431 FbDataPrivate *priv;
432 GList *l;
433 GList *prev;
434 GSList *msgs = NULL;
436 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
437 priv = fata->priv;
438 l = priv->msgs->tail;
440 while (l != NULL) {
441 msg = l->data;
442 prev = l->prev;
444 if (msg->uid == uid) {
445 msgs = g_slist_prepend(msgs, msg);
446 g_queue_delete_link(priv->msgs, l);
449 l = prev;
452 return msgs;
455 FbDataImage *
456 fb_data_image_add(FbData *fata, const gchar *url, FbDataImageFunc func,
457 gpointer data, GDestroyNotify dunc)
459 FbDataImage *img;
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);
467 priv = img->priv;
469 priv->fata = fata;
470 priv->url = g_strdup(url);
471 priv->func = func;
472 priv->data = data;
473 priv->dunc = dunc;
475 g_hash_table_insert(fata->priv->imgs, img, img);
476 return img;
479 gboolean
480 fb_data_image_get_active(FbDataImage *img)
482 FbDataImagePrivate *priv;
484 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), FALSE);
485 priv = img->priv;
487 return priv->active;
490 gpointer
491 fb_data_image_get_data(FbDataImage *img)
493 FbDataImagePrivate *priv;
495 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
496 priv = img->priv;
498 return priv->data;
501 FbData *
502 fb_data_image_get_fata(FbDataImage *img)
504 FbDataImagePrivate *priv;
506 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
507 priv = img->priv;
509 return priv->fata;
512 const guint8 *
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);
518 priv = img->priv;
520 if (size != NULL) {
521 *size = priv->size;
524 return priv->image;
527 guint8 *
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);
533 priv = img->priv;
535 if (size != NULL) {
536 *size = priv->size;
539 if (priv->size < 1) {
540 return NULL;
543 return g_memdup(priv->image, priv->size);
546 const gchar *
547 fb_data_image_get_url(FbDataImage *img)
549 FbDataImagePrivate *priv;
551 g_return_val_if_fail(FB_IS_DATA_IMAGE(img), NULL);
552 priv = img->priv;
554 return priv->url;
557 static void
558 fb_data_image_cb(G_GNUC_UNUSED SoupSession *session, SoupMessage *res,
559 gpointer data)
561 FbDataImage *img = data;
562 FbDataImagePrivate *priv = img->priv;
563 GError *err = NULL;
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);
573 } else {
574 g_error_free(err);
577 g_object_unref(img);
580 void
581 fb_data_image_queue(FbData *fata)
583 const gchar *url;
584 FbDataImage *img;
585 FbDataPrivate *priv;
586 GHashTableIter iter;
587 guint active = 0;
589 g_return_if_fail(FB_IS_DATA(fata));
590 priv = fata->priv;
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)) {
595 active++;
599 if (active >= FB_DATA_ICON_MAX) {
600 return;
603 g_hash_table_iter_init(&iter, priv->imgs);
605 while (g_hash_table_iter_next(&iter, (gpointer *) &img, NULL)) {
606 SoupMessage *msg;
608 if (fb_data_image_get_active(img)) {
609 continue;
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) {
620 break;