1 /*
2 * Copyright 2014-2016 James Geboski <jgeboski@gmail.com>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <string.h>
19
20 #include "facebook-api.h"
21 #include "facebook-data.h"
22
23 struct _FbDataPrivate
24 {
25 FbApi *api;
26 struct im_connection *ic;
27 GQueue *msgs;
28 GQueue *tids;
29 GHashTable *evs;
30 GHashTable *gcs;
31 };
32
33 static const gchar *fb_props_strs[] = {
34 "cid",
35 "did",
36 "stoken",
37 "token"
38 };
39
40 G_DEFINE_TYPE_WITH_PRIVATE(FbData, fb_data, G_TYPE_OBJECT);
41
42 static void
fb_data_dispose(GObject * obj)43 fb_data_dispose(GObject *obj)
44 {
45 FbDataPrivate *priv = FB_DATA(obj)->priv;
46 GHashTableIter iter;
47 gpointer ptr;
48
49 g_object_unref(priv->api);
50 g_hash_table_iter_init(&iter, priv->evs);
51
52 while (g_hash_table_iter_next(&iter, NULL, &ptr)) {
53 g_hash_table_iter_remove(&iter);
54 b_event_remove(GPOINTER_TO_UINT(ptr));
55 }
56
57 g_hash_table_iter_init(&iter, priv->gcs);
58
59 while (g_hash_table_iter_next(&iter, NULL, &ptr)) {
60 g_hash_table_iter_remove(&iter);
61 imcb_chat_free(ptr);
62 }
63
64 g_queue_free_full(priv->msgs, (GDestroyNotify) fb_api_message_free);
65 g_queue_free_full(priv->tids, g_free);
66
67 g_hash_table_destroy(priv->evs);
68 g_hash_table_destroy(priv->gcs);
69 }
70
71 static void
fb_data_class_init(FbDataClass * klass)72 fb_data_class_init(FbDataClass *klass)
73 {
74 GObjectClass *gklass = G_OBJECT_CLASS(klass);
75
76 gklass->dispose = fb_data_dispose;
77 }
78
79 static void
fb_data_init(FbData * fata)80 fb_data_init(FbData *fata)
81 {
82 FbDataPrivate *priv;
83
84 priv = fb_data_get_instance_private(fata);
85 fata->priv = priv;
86
87 priv->api = fb_api_new();
88 priv->msgs = g_queue_new();
89 priv->tids = g_queue_new();
90 priv->evs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
91 priv->gcs = g_hash_table_new(g_direct_hash, g_direct_equal);
92 }
93
94 FbData *
fb_data_new(account_t * acct)95 fb_data_new(account_t *acct)
96 {
97 FbData *fata;
98 FbDataPrivate *priv;
99
100 fata = g_object_new(FB_TYPE_DATA, NULL);
101 priv = fata->priv;
102
103 priv->ic = imcb_new(acct);
104 priv->ic->proto_data = fata;
105 return fata;
106 }
107
108 gboolean
fb_data_load(FbData * fata)109 fb_data_load(FbData *fata)
110 {
111 account_t *acct;
112 const gchar *str;
113 FbDataPrivate *priv;
114 FbId id;
115 gboolean ret = TRUE;
116 guint i;
117 guint64 uint;
118 GValue val = G_VALUE_INIT;
119 int num;
120
121 g_return_val_if_fail(FB_IS_DATA(fata), FALSE);
122 priv = fata->priv;
123 acct = priv->ic->acc;
124
125 for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
126 str = set_getstr(&acct->set, fb_props_strs[i]);
127
128 if (str == NULL) {
129 ret = FALSE;
130 }
131
132 g_value_init(&val, G_TYPE_STRING);
133 g_value_set_string(&val, str);
134 g_object_set_property(G_OBJECT(priv->api), fb_props_strs[i],
135 &val);
136 g_value_unset(&val);
137 }
138
139 str = set_getstr(&acct->set, "mid");
140
141 if (str != NULL) {
142 uint = g_ascii_strtoull(str, NULL, 10);
143 g_value_init(&val, G_TYPE_UINT64);
144 g_value_set_uint64(&val, uint);
145 g_object_set_property(G_OBJECT(priv->api), "mid", &val);
146 g_value_unset(&val);
147 } else {
148 ret = FALSE;
149 }
150
151 str = set_getstr(&acct->set, "uid");
152
153 if (str != NULL) {
154 id = FB_ID_FROM_STR(str);
155 g_value_init(&val, FB_TYPE_ID);
156 g_value_set_int64(&val, id);
157 g_object_set_property(G_OBJECT(priv->api), "uid", &val);
158 g_value_unset(&val);
159 } else {
160 ret = FALSE;
161 }
162
163 num = set_getint(&acct->set, "tweak");
164 if (num != 0) {
165 g_value_init(&val, G_TYPE_INT);
166 g_value_set_int(&val, num);
167 g_object_set_property(G_OBJECT(priv->api), "tweak", &val);
168 g_value_unset(&val);
169 }
170
171 num = set_getbool(&acct->set, "work");
172 if (num != 0) {
173 g_value_init(&val, G_TYPE_BOOLEAN);
174 g_value_set_boolean(&val, num);
175 g_object_set_property(G_OBJECT(priv->api), "work", &val);
176 g_value_unset(&val);
177 }
178
179 fb_api_rehash(priv->api);
180 return ret;
181 }
182
183 void
fb_data_save(FbData * fata)184 fb_data_save(FbData *fata)
185 {
186 account_t *acct;
187 const gchar *str;
188 FbDataPrivate *priv;
189 gchar *dup;
190 guint i;
191 guint64 uint;
192 GValue val = G_VALUE_INIT;
193
194 g_return_if_fail(FB_IS_DATA(fata));
195 priv = fata->priv;
196 acct = priv->ic->acc;
197
198 for (i = 0; i < G_N_ELEMENTS(fb_props_strs); i++) {
199 g_value_init(&val, G_TYPE_STRING);
200 g_object_get_property(G_OBJECT(priv->api), fb_props_strs[i],
201 &val);
202 str = g_value_get_string(&val);
203 set_setstr(&acct->set, fb_props_strs[i], (gchar *) str);
204 g_value_unset(&val);
205 }
206
207 g_value_init(&val, G_TYPE_UINT64);
208 g_object_get_property(G_OBJECT(priv->api), "mid", &val);
209 uint = g_value_get_uint64(&val);
210 g_value_unset(&val);
211
212 dup = g_strdup_printf("%" G_GINT64_FORMAT, uint);
213 set_setstr(&acct->set, "mid", dup);
214 g_free(dup);
215
216 g_value_init(&val, G_TYPE_INT64);
217 g_object_get_property(G_OBJECT(priv->api), "uid", &val);
218 uint = g_value_get_int64(&val);
219 g_value_unset(&val);
220
221 dup = g_strdup_printf("%" FB_ID_FORMAT, uint);
222 set_setstr(&acct->set, "uid", dup);
223 g_free(dup);
224 }
225
226 void
fb_data_add_groupchat(FbData * fata,struct groupchat * gc)227 fb_data_add_groupchat(FbData *fata, struct groupchat *gc)
228 {
229 FbDataPrivate *priv;
230
231 g_return_if_fail(FB_IS_DATA(fata));
232 priv = fata->priv;
233
234 g_hash_table_replace(priv->gcs, gc, gc);
235 }
236
237 void
fb_data_remove_groupchat(FbData * fata,struct groupchat * gc)238 fb_data_remove_groupchat(FbData *fata, struct groupchat *gc)
239 {
240 FbDataPrivate *priv;
241
242 g_return_if_fail(FB_IS_DATA(fata));
243 priv = fata->priv;
244
245 g_hash_table_remove(priv->gcs, gc);
246 }
247
248 void
fb_data_add_thread_head(FbData * fata,FbId tid)249 fb_data_add_thread_head(FbData *fata, FbId tid)
250 {
251 FbDataPrivate *priv;
252 FbId *dtid;
253
254 g_return_if_fail(FB_IS_DATA(fata));
255 priv = fata->priv;
256
257 dtid = g_memdup(&tid, sizeof tid);
258 g_queue_push_head(priv->tids, dtid);
259 }
260
261 void
fb_data_add_thread_tail(FbData * fata,FbId tid)262 fb_data_add_thread_tail(FbData *fata, FbId tid)
263 {
264 FbDataPrivate *priv;
265 FbId *dtid;
266
267 g_return_if_fail(FB_IS_DATA(fata));
268 priv = fata->priv;
269
270 dtid = g_memdup(&tid, sizeof tid);
271 g_queue_push_tail(priv->tids, dtid);
272 }
273
274 void
fb_data_clear_threads(FbData * fata)275 fb_data_clear_threads(FbData *fata)
276 {
277 FbDataPrivate *priv;
278 FbId *tid;
279
280 g_return_if_fail(FB_IS_DATA(fata));
281 priv = fata->priv;
282
283 while (!g_queue_is_empty(priv->tids)) {
284 tid = g_queue_pop_head(priv->tids);
285 g_free(tid);
286 }
287 }
288
289 FbId
fb_data_get_thread(FbData * fata,guint n)290 fb_data_get_thread(FbData *fata, guint n)
291 {
292 FbDataPrivate *priv;
293 FbId *tid;
294
295 g_return_val_if_fail(FB_IS_DATA(fata), 0);
296 priv = fata->priv;
297
298 tid = g_queue_peek_nth(priv->tids, n);
299
300 if (tid == NULL) {
301 return 0;
302 }
303
304 return *tid;
305 }
306
307 void
fb_data_add_timeout(FbData * fata,const gchar * name,guint interval,b_event_handler func,gpointer data)308 fb_data_add_timeout(FbData *fata, const gchar *name, guint interval,
309 b_event_handler func, gpointer data)
310 {
311 FbDataPrivate *priv;
312 gchar *key;
313 guint id;
314
315 g_return_if_fail(FB_IS_DATA(fata));
316 priv = fata->priv;
317
318 fb_data_clear_timeout(fata, name, TRUE);
319
320 key = g_strdup(name);
321 id = b_timeout_add(interval, func, data);
322 g_hash_table_replace(priv->evs, key, GUINT_TO_POINTER(id));
323 }
324
325 void
fb_data_clear_timeout(FbData * fata,const gchar * name,gboolean remove)326 fb_data_clear_timeout(FbData *fata, const gchar *name, gboolean remove)
327 {
328 FbDataPrivate *priv;
329 gpointer ptr;
330 guint id;
331
332 g_return_if_fail(FB_IS_DATA(fata));
333 priv = fata->priv;
334
335 ptr = g_hash_table_lookup(priv->evs, name);
336 id = GPOINTER_TO_UINT(ptr);
337
338 if ((id > 0) && remove) {
339 b_event_remove(id);
340 }
341
342 g_hash_table_remove(priv->evs, name);
343 }
344
345 FbApi *
fb_data_get_api(FbData * fata)346 fb_data_get_api(FbData *fata)
347 {
348 FbDataPrivate *priv;
349
350 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
351 priv = fata->priv;
352
353 return priv->api;
354 }
355
356 struct im_connection *
fb_data_get_connection(FbData * fata)357 fb_data_get_connection(FbData *fata)
358 {
359 FbDataPrivate *priv;
360
361 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
362 priv = fata->priv;
363
364 return priv->ic;
365 }
366
367 void
fb_data_add_message(FbData * fata,FbApiMessage * msg)368 fb_data_add_message(FbData *fata, FbApiMessage *msg)
369 {
370 FbDataPrivate *priv;
371
372 g_return_if_fail(FB_IS_DATA(fata));
373 priv = fata->priv;
374
375 g_queue_push_tail(priv->msgs, msg);
376 }
377
378 void
fb_data_remove_message(FbData * fata,FbApiMessage * msg)379 fb_data_remove_message(FbData *fata, FbApiMessage *msg)
380 {
381 FbDataPrivate *priv;
382
383 g_return_if_fail(FB_IS_DATA(fata));
384 priv = fata->priv;
385
386 g_queue_remove(priv->msgs, msg);
387 }
388
389 GSList *
fb_data_take_messages(FbData * fata,FbId uid)390 fb_data_take_messages(FbData *fata, FbId uid)
391 {
392 FbApiMessage *msg;
393 FbDataPrivate *priv;
394 GList *l;
395 GList *prev;
396 GSList *msgs = NULL;
397
398 g_return_val_if_fail(FB_IS_DATA(fata), NULL);
399 priv = fata->priv;
400 l = priv->msgs->tail;
401
402 while (l != NULL) {
403 msg = l->data;
404 prev = l->prev;
405
406 if (msg->uid == uid) {
407 msgs = g_slist_prepend(msgs, msg);
408 g_queue_delete_link(priv->msgs, l);
409 }
410
411 l = prev;
412 }
413
414 return msgs;
415 }
416