diff options
author | jgeboski <jgeboski@gmail.com> | 2015-08-24 17:01:16 -0400 |
---|---|---|
committer | jgeboski <jgeboski@gmail.com> | 2015-08-24 17:01:16 -0400 |
commit | 53cedfaca78278a64cc347e8ed51bb67363b3dcc (patch) | |
tree | dd2c6cac0c3d5d4af1cccaa9cbbc7a6ca4522572 /facebook/facebook.c | |
parent | 60a42307f24c617029efbb7bcd432d162706c692 (diff) | |
download | bitlbee-facebook-53cedfaca78278a64cc347e8ed51bb67363b3dcc.tar.gz bitlbee-facebook-53cedfaca78278a64cc347e8ed51bb67363b3dcc.tar.bz2 bitlbee-facebook-53cedfaca78278a64cc347e8ed51bb67363b3dcc.tar.xz |
Imported changes from purple-facebook
Diffstat (limited to 'facebook/facebook.c')
-rw-r--r-- | facebook/facebook.c | 1274 |
1 files changed, 608 insertions, 666 deletions
diff --git a/facebook/facebook.c b/facebook/facebook.c index c25232e..61bc04d 100644 --- a/facebook/facebook.c +++ b/facebook/facebook.c @@ -15,187 +15,341 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "facebook.h" +#include <bitlbee.h> + +#include "facebook-api.h" +#include "facebook-data.h" +#include "facebook-mqtt.h" #include "facebook-util.h" -/** - * Implemented #fb_api_funcs->error(). - * - * @param api The #fb_api. - * @param err The #GError. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_error(fb_api_t *api, GError *err, gpointer data) +static void +fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data); + +static void +fb_cb_api_auth(FbApi *api, gpointer data) { - fb_data_t *fata = data; + FbData *fata = data; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); - FB_UTIL_DEBUGLN("Error: %s", err->message); - imcb_error(fata->ic, "%s", err->message); - imc_logout(fata->ic, TRUE); + imcb_log(ic, "Fetching contacts"); + fb_data_save(fata); + fb_api_contacts(api); } -/** - * Implemented #fb_api_funcs->auth(). - * - * @param api The #fb_api. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_auth(fb_api_t *api, gpointer data) +static void +fb_cb_api_connect(FbApi *api, gpointer data) { - fb_data_t *fata = data; - account_t *acc = fata->ic->acc; - gchar uid[FB_ID_STRMAX]; + account_t *acct; + FbData *fata = data; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); + acct = ic->acc; - FB_ID_TO_STR(api->uid, uid); - set_setstr(&acc->set, "uid", uid); - set_setstr(&acc->set, "token", api->token); - imcb_log(fata->ic, "Authentication finished"); + fb_data_save(fata); + imcb_connected(ic); - account_off(acc->bee, acc); - account_on(acc->bee, acc); + if (set_getbool(&acct->set, "show_unread")) { + fb_api_unread(api); + } } -/** - * Implemented #fb_api_funcs->connect(). - * - * @param api The #fb_api. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_connect(fb_api_t *api, gpointer data) +static void +fb_cb_api_contact(FbApi *api, FbApiUser *user, gpointer data) { - fb_data_t *fata = data; - account_t *acc = fata->ic->acc; + FbData *fata = data; + gchar uid[FB_ID_STRMAX]; + GSList *msgs; + struct im_connection *ic; - imcb_connected(fata->ic); - set_setstr(&acc->set, "stoken", api->stoken); + ic = fb_data_get_connection(fata); + FB_ID_TO_STR(user->uid, uid); + + if (bee_user_by_handle(ic->bee, ic, uid) == NULL) { + bee_user_new(ic->bee, ic, uid, BEE_USER_LOCAL); + imcb_buddy_nick_hint(ic, uid, user->name); + imcb_rename_buddy(ic, uid, user->name); + } + + msgs = fb_data_take_messages(fata, user->uid); + + if (msgs != NULL) { + fb_cb_api_messages(api, msgs, fata); + g_slist_free_full(msgs, (GDestroyNotify) fb_api_message_free); + } } -/** - * Implemented #fb_api_funcs->contacts(). - * - * @param api The #fb_api. - * @param users The #GSList of #fb_api_user. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_contacts(fb_api_t *api, GSList *users, gpointer data) +static gboolean +fb_cb_sync_contacts(gpointer data, gint fd, b_input_condition cond) +{ + FbApi *api; + FbData *fata = data; + + api = fb_data_get_api(fata); + fb_data_clear_timeout(fata, "sync-contacts", FALSE); + fb_api_contacts(api); + return FALSE; +} + +static void +fb_cb_api_contacts(FbApi *api, GSList *users, gboolean complete, gpointer data) { - fb_data_t *fata = data; - fb_api_user_t *user; - GSList *l; - gchar uid[FB_ID_STRMAX]; + account_t *acct; + bee_user_t *bu; + FbApiUser *user; + FbData *fata = data; + FbId muid; + gchar uid[FB_ID_STRMAX]; + gint sync; + GSList *l; + GValue val = G_VALUE_INIT; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); + + g_value_init(&val, FB_TYPE_ID); + g_object_get_property(G_OBJECT(api), "uid", &val); + muid = g_value_get_int64(&val); + g_value_unset(&val); for (l = users; l != NULL; l = l->next) { user = l->data; FB_ID_TO_STR(user->uid, uid); - imcb_add_buddy(fata->ic, uid, NULL); - imcb_buddy_nick_hint(fata->ic, uid, user->name); - imcb_rename_buddy(fata->ic, uid, user->name); + + if (G_UNLIKELY(user->uid == muid)) { + continue; + } + + imcb_add_buddy(ic, uid, NULL); + imcb_buddy_nick_hint(ic, uid, user->name); + imcb_rename_buddy(ic, uid, user->name); + + bu = imcb_buddy_by_handle(ic, uid); + bu->data = GINT_TO_POINTER(TRUE); + } + + if (!complete) { + return; + } + + l = ic->bee->users; + + while (l != NULL) { + bu = l->data; + l = l->next; + + if (bu->ic != ic) { + continue; + } + + if (GPOINTER_TO_INT(bu->data)) { + bu->data = NULL; + } else { + imcb_remove_buddy(ic, bu->handle, NULL); + } } - imcb_log(fata->ic, "Establishing connection"); - fb_api_connect(fata->api); + if (!(ic->flags & OPT_LOGGED_IN)) { + imcb_log(ic, "Connecting"); + fb_api_connect(api, FALSE); + } + + acct = ic->acc; + sync = set_getint(&acct->set, "sync_interval"); + + if (sync < 5) { + set_setint(&acct->set, "sync_interval", 5); + sync = 5; + } + + sync *= 60 * 1000; + fb_data_add_timeout(fata, "sync-contacts", sync, fb_cb_sync_contacts, + fata); } -/** - * Implemented #fb_api_funcs->message(). - * - * @param api The #fb_api. - * @param msgs The #GSList of #fb_api_msg. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_message(fb_api_t *api, GSList *msgs, gpointer data) +static void +fb_cb_api_error(FbApi *api, GError *error, gpointer data) +{ + FbData *fata = data; + gboolean recon; + struct im_connection *ic; + + if (g_error_matches(error, FB_API_ERROR, FB_API_ERROR_QUEUE)) { + /* Save the reset data */ + fb_data_save(fata); + } + + recon = ((error->domain != FB_HTTP_ERROR) || + (error->code < 400) || + (error->code > 500)) && + !g_error_matches(error, FB_API_ERROR, FB_API_ERROR_AUTH); + + ic = fb_data_get_connection(fata); + fb_util_debug_error("%s", error->message); + imcb_error(ic, "%s", error->message); + imc_logout(ic, recon); +} + +static void +fb_cb_api_events(FbApi *api, GSList *events, gpointer data) { - fb_data_t *fata = data; - fb_api_msg_t *msg; + FbApiEvent *event; + FbData *fata = data; + gchar tid[FB_ID_STRMAX]; + gchar uid[FB_ID_STRMAX]; + GHashTable *fetch; + GHashTableIter iter; + GSList *l; struct groupchat *gc; - GSList *l; - gchar uid[FB_ID_STRMAX]; - gchar tid[FB_ID_STRMAX]; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); + fetch = g_hash_table_new(fb_id_hash, fb_id_equal); + + for (l = events; l != NULL; l = l->next) { + event = l->data; + + FB_ID_TO_STR(event->tid, tid); + gc = bee_chat_by_title(ic->bee, ic, tid); + + if (gc == NULL) { + continue; + } + + FB_ID_TO_STR(event->uid, uid); + + switch (event->type) { + case FB_API_EVENT_TYPE_THREAD_USER_ADDED: + if (bee_user_by_handle(ic->bee, ic, uid) == NULL) { + g_hash_table_insert(fetch, &event->tid, event); + break; + } + + imcb_chat_add_buddy(gc, uid); + break; + + case FB_API_EVENT_TYPE_THREAD_USER_REMOVED: + imcb_chat_remove_buddy(gc, uid, NULL); + break; + } + } + + g_hash_table_iter_init(&iter, fetch); + + while (g_hash_table_iter_next(&iter, NULL, (gpointer) &event)) { + fb_api_thread(api, event->tid); + } + + g_hash_table_destroy(fetch); +} + +static void +fb_cb_api_messages(FbApi *api, GSList *msgs, gpointer data) +{ + account_t *acct; + FbApiMessage *msg; + FbData *fata = data; + gboolean mark; + gchar tid[FB_ID_STRMAX]; + gchar uid[FB_ID_STRMAX]; + GSList *l; + struct groupchat *gc; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); + acct = ic->acc; + mark = set_getbool(&acct->set, "mark_read"); for (l = msgs; l != NULL; l = l->next) { msg = l->data; FB_ID_TO_STR(msg->uid, uid); + if (msg->flags & FB_API_MESSAGE_FLAG_SELF) { + continue; + } + + if (bee_user_by_handle(ic->bee, ic, uid) == NULL) { + msg = fb_api_message_dup(msg, TRUE); + fb_data_add_message(fata, msg); + fb_api_contact(api, msg->uid); + continue; + } + if (msg->tid == 0) { - imcb_buddy_msg(fata->ic, uid, (gchar*) msg->text, 0, 0); + if (mark) { + fb_api_read(api, msg->uid, FALSE); + } + + imcb_buddy_msg(ic, uid, (gchar*) msg->text, 0, 0); continue; } FB_ID_TO_STR(msg->tid, tid); - gc = bee_chat_by_title(fata->ic->bee, fata->ic, tid); + gc = bee_chat_by_title(ic->bee, ic, tid); + + if (gc != NULL) { + if (mark) { + fb_api_read(api, msg->tid, TRUE); + } - if (gc != NULL) imcb_chat_msg(gc, uid, (gchar*) msg->text, 0, 0); + } } } -/** - * Implemented #fb_api_funcs->presence(). - * - * @param api The #fb_api. - * @param press The #GSList of #fb_api_msg. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_presence(fb_api_t *api, GSList *press, gpointer data) +static void +fb_cb_api_presences(FbApi *api, GSList *press, gpointer data) { - fb_data_t *fata = data; - fb_api_pres_t *pres; - GSList *l; - guint flags; - gchar uid[FB_ID_STRMAX]; + FbApiPresence *pres; + FbData *fata = data; + gchar uid[FB_ID_STRMAX]; + GSList *l; + guint flags; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); for (l = press; l != NULL; l = l->next) { - pres = l->data; - flags = 0; + pres = l->data; + FB_ID_TO_STR(pres->uid, uid); - if (pres->active) - flags |= BEE_USER_ONLINE; + if (bee_user_by_handle(ic->bee, ic, uid) == NULL) { + continue; + } + + if (pres->active) { + flags = BEE_USER_ONLINE; + } else { + flags = 0; + } FB_ID_TO_STR(pres->uid, uid); - imcb_buddy_status(fata->ic, uid, flags, NULL, NULL); + imcb_buddy_status(ic, uid, flags, NULL, NULL); } } -/** - * Implemented #fb_api_funcs->thread_create(). - * - * @param api The #fb_api. - * @param tid The thread #fb_id. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_thread_create(fb_api_t *api, fb_id_t tid, gpointer data) -{ - fb_data_t *fata = data; - account_t *acc = fata->ic->acc; - - fata->tids = g_slist_prepend(fata->tids, g_memdup(&tid, sizeof tid)); - imcb_log(fata->ic, "Created chat thread %" FB_ID_FORMAT, tid); - imcb_log(fata->ic, "Join: fbjoin %s %d <channel-name>", acc->tag, 1); -} - -/** - * Implemented #fb_api_funcs->thread_info(). - * - * @param api The #fb_api. - * @param thrd The #fb_api_thread. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_thread_info(fb_api_t *api, fb_api_thread_t *thrd, - gpointer data) +static void +fb_cb_api_thread(FbApi *api, FbApiThread *thrd, gpointer data) { - fb_data_t *fata = data; - fb_api_user_t *user; - bee_user_t *bu; + bee_user_t *bu; + FbApiUser *user; + FbData *fata = data; + gchar id[FB_ID_STRMAX]; + GList *h; + GSList *l; + GString *gstr; struct groupchat *gc; - GSList *l; - GString *gstr; - gchar id[FB_ID_STRMAX]; + struct im_connection *ic; FB_ID_TO_STR(thrd->tid, id); - gc = bee_chat_by_title(fata->ic->bee, fata->ic, id); + ic = fb_data_get_connection(fata); + gc = bee_chat_by_title(ic->bee, ic, id); - if (G_UNLIKELY(gc == NULL)) + if (G_UNLIKELY(gc == NULL)) { return; + } if (thrd->topic == NULL) { gstr = g_string_new(NULL); @@ -203,8 +357,9 @@ static void fb_cb_api_thread_info(fb_api_t *api, fb_api_thread_t *thrd, for (l = thrd->users; l != NULL; l = l->next) { user = l->data; - if (gstr->len > 0) + if (gstr->len > 0) { g_string_append(gstr, ", "); + } g_string_append(gstr, user->name); } @@ -212,220 +367,146 @@ static void fb_cb_api_thread_info(fb_api_t *api, fb_api_thread_t *thrd, imcb_chat_topic(gc, NULL, gstr->str, 0); g_string_free(gstr, TRUE); } else { - imcb_chat_topic(gc, NULL, (gchar*) thrd->topic, 0); + imcb_chat_topic(gc, NULL, (gchar *) thrd->topic, 0); } for (l = thrd->users; l != NULL; l = l->next) { user = l->data; FB_ID_TO_STR(user->uid, id); - bu = bee_user_by_handle(fata->ic->bee, fata->ic, id); + h = g_list_find_custom(gc->in_room, id, (GCompareFunc) g_strcmp0); - imcb_chat_add_buddy(gc, id); + if (h != NULL) { + continue; + } + + bu = bee_user_by_handle(ic->bee, ic, id); if (bu == NULL) { - imcb_buddy_nick_hint(fata->ic, id, user->name); - imcb_rename_buddy(fata->ic, id, user->name); + bee_user_new(ic->bee, ic, id, BEE_USER_LOCAL); + imcb_buddy_nick_hint(ic, id, user->name); + imcb_rename_buddy(ic, id, user->name); } + + imcb_chat_add_buddy(gc, id); } } -/** - * Implemented #fb_api_funcs->thread_list(). - * - * @param api The #fb_api. - * @param thrds The #GSList of #fb_api_thread. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_thread_list(fb_api_t *api, GSList *thrds, gpointer data) +static void +fb_cb_api_thread_create(FbApi *api, FbId tid, gpointer data) { - fb_data_t *fata = data; - fb_api_thread_t *thrd; - fb_api_user_t *user; - GSList *phrds; - GSList *l; - GSList *m; - GString *ln; - gpointer mptr; - guint i; - guint j; - - g_slist_free_full(fata->tids, g_free); - fata->tids = NULL; - phrds = NULL; + account_t *acct; + FbData *fata = data; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); + acct = ic->acc; + + fb_data_add_thread_head(fata, tid); + imcb_log(ic, "Created chat thread %" FB_ID_FORMAT, tid); + imcb_log(ic, "Join: fbjoin %s %d <channel-name>", acct->tag, 1); +} + +static void +fb_cb_api_threads(FbApi *api, GSList *thrds, gpointer data) +{ + FbApiThread *thrd; + FbApiUser *user; + FbData *fata = data; + GSList *phrds = NULL; + GSList *l; + GSList *m; + GString *lines; + guint i; + guint j; + struct im_connection *ic; + + ic = fb_data_get_connection(fata); + fb_data_clear_threads(fata); for (l = thrds, i = 0; (l != NULL) && (i < 25); l = l->next, i++) { thrd = l->data; - if (g_slist_length(thrd->users) >= 2) + if (g_slist_length(thrd->users) >= 2) { phrds = g_slist_prepend(phrds, thrd); + } } if (phrds == NULL) { - imcb_log(fata->ic, "No chats to display."); + imcb_log(ic, "No chats to display."); return; } - ln = g_string_new(NULL); - imcb_log(fata->ic, "%2s %-20s %s", "ID", "Topic", "Participants"); + lines = g_string_new(NULL); + imcb_log(ic, "%2s %-20s %s", "ID", "Topic", "Participants"); phrds = g_slist_reverse(phrds); for (l = phrds, i = 1; l != NULL; l = l->next, i++) { thrd = l->data; - - if (g_slist_length(thrd->users) < 2) - continue; - - mptr = g_memdup(&thrd->tid, sizeof thrd->tid); - fata->tids = g_slist_prepend(fata->tids, mptr); - - g_string_printf(ln, "%2d", i); + fb_data_add_thread_tail(fata, thrd->tid); + g_string_printf(lines, "%2d", i); if (thrd->topic != NULL) { if (strlen(thrd->topic) > 20) { for (j = 16; g_ascii_isspace(thrd->topic[j]) && (j > 0); j--); - g_string_append_printf(ln, " %-.*s...", ++j, thrd->topic); - g_string_append_printf(ln, "%*s", 17 - j, ""); + g_string_append_printf(lines, " %-.*s...", ++j, thrd->topic); + g_string_append_printf(lines, "%*s", 17 - j, ""); } else { - g_string_append_printf(ln, " %-20s", thrd->topic); + g_string_append_printf(lines, " %-20s", thrd->topic); } } else { - g_string_append_printf(ln, " %20s", ""); + g_string_append_printf(lines, " %20s", ""); } for (m = thrd->users, j = 0; (m != NULL) && (j < 3); m = m->next, j++) { user = m->data; - g_string_append(ln, (j != 0) ? ", " : " "); - g_string_append(ln, user->name); + g_string_append(lines, (j != 0) ? ", " : " "); + g_string_append(lines, user->name); } - if (m != NULL) - g_string_append(ln, "..."); + if (m != NULL) { + g_string_append(lines, "..."); + } - imcb_log(fata->ic, "%s", ln->str); + imcb_log(ic, "%s", lines->str); } - fata->tids = g_slist_reverse(fata->tids); - g_string_free(ln, TRUE); + g_string_free(lines, TRUE); g_slist_free(phrds); } -/** - * Implemented #fb_api_funcs->typing(). - * - * @param api The #fb_api. - * @param typg The #fb_api_typing. - * @param data The user defined data, which is #fb_data. - **/ -static void fb_cb_api_typing(fb_api_t *api, fb_api_typing_t *typg, - gpointer data) +static void +fb_cb_api_typing(FbApi *api, FbApiTyping *typg, gpointer data) { - fb_data_t *fata = data; - guint32 flags; - gchar uid[FB_ID_STRMAX]; + FbData *fata = data; + gchar uid[FB_ID_STRMAX]; + guint32 flags; + struct im_connection *ic; FB_ID_TO_STR(typg->uid, uid); + ic = fb_data_get_connection(fata); flags = typg->state ? OPT_TYPING : 0; - imcb_buddy_typing(fata->ic, uid, flags); + imcb_buddy_typing(ic, uid, flags); } -/** - * Creates a new #fb_data with an #account. The returned #fb_data - * should be freed with #fb_data_free() when no longer needed. - * - * @param acc The #account. - * - * @return The #fb_data or NULL on error. - **/ -fb_data_t *fb_data_new(account_t *acc) -{ - fb_data_t *fata; - gchar *uid; - - static const fb_api_funcs_t funcs = { - .error = fb_cb_api_error, - .auth = fb_cb_api_auth, - .connect = fb_cb_api_connect, - .contacts = fb_cb_api_contacts, - .message = fb_cb_api_message, - .presence = fb_cb_api_presence, - .thread_create = fb_cb_api_thread_create, - .thread_info = fb_cb_api_thread_info, - .thread_list = fb_cb_api_thread_list, - .typing = fb_cb_api_typing - }; - - g_return_val_if_fail(acc != NULL, NULL); - - fata = g_new0(fb_data_t, 1); - fata->api = fb_api_new(&funcs, fata); - - fata->ic = imcb_new(acc); - fata->ic->proto_data = fata; - - uid = set_getstr(&acc->set, "uid"); - - if (uid != NULL) - fata->api->uid = FB_ID_FROM_STR(uid); - - fata->api->token = g_strdup(set_getstr(&acc->set, "token")); - fata->api->stoken = g_strdup(set_getstr(&acc->set, "stoken")); - fata->api->cid = g_strdup(set_getstr(&acc->set, "cid")); - fata->api->mid = g_strdup(set_getstr(&acc->set, "mid")); - fata->api->cuid = g_strdup(set_getstr(&acc->set, "cuid")); - - fb_api_rehash(fata->api); - - set_setstr(&acc->set, "cid", fata->api->cid); - set_setstr(&acc->set, "mid", fata->api->mid); - set_setstr(&acc->set, "cuid", fata->api->cuid); - - return fata; -} - -/** - * Frees all memory used by a #fb_data. - * - * @param sata The #fb_data. - **/ -void fb_data_free(fb_data_t *fata) -{ - if (G_UNLIKELY(fata == NULL)) - return; - - fb_api_free(fata->api); - g_slist_free_full(fata->tids, g_free); - g_slist_free_full(fata->gcs, (GDestroyNotify) imcb_chat_free); - g_free(fata); -} - -/** - * Creates a new #groupchat and adds it to the #fb_data. The returned - * #groupchat should be freed with #fb_data_groupchat_free() when no - * longer needed. - * - * @param ic The #im_connection. - * @param tid The thread #fb_id. - * @param name The name of the channel. - * - * @return The #groupchat or NULL on error. - **/ -struct groupchat *fb_data_groupchat_new(struct im_connection *ic, - fb_id_t tid, - const gchar *name) +static struct groupchat * +fb_data_groupchat_new(struct im_connection *ic, FbId tid, const gchar *name) { - fb_data_t *fata = ic->proto_data; + FbApi *api; + FbData *fata = ic->proto_data; + gchar stid[FB_ID_STRMAX]; + irc_channel_t *ch; struct groupchat *gc; - irc_channel_t *ch; - gchar stid[FB_ID_STRMAX]; FB_ID_TO_STR(tid, stid); - if (bee_chat_by_title(ic->bee, ic, stid) != NULL) + if (bee_chat_by_title(ic->bee, ic, stid) != NULL) { return NULL; + } if (name != NULL) { - if (strchr(CTYPES, name[0]) != NULL) + if (strchr(CTYPES, name[0]) != NULL) { name++; + } /* Let the hackery being... */ gc = imcb_chat_new(ic, stid); @@ -445,385 +526,257 @@ struct groupchat *fb_data_groupchat_new(struct im_connection *ic, } gc = imcb_chat_new(ic, stid); - ch = gc->ui_data; - fata->gcs = g_slist_prepend(fata->gcs, gc); + fb_data_add_groupchat(fata, gc); + ch = gc->ui_data; ch->flags &= ~IRC_CHANNEL_CHAT_PICKME; - imcb_chat_add_buddy(gc, ic->acc->user); - fb_api_thread_info(fata->api, tid); + api = fb_data_get_api(fata); + imcb_chat_add_buddy(gc, ic->acc->user); + fb_api_thread(api, tid); return gc; } -/** - * Frees all memory used by a #groupchat and removes it from the - * #fb_data. - * - * @param gc The #groupchat. - **/ -void fb_data_groupchat_free(struct groupchat *gc) -{ - fb_data_t *fata; - - if (G_UNLIKELY(gc == NULL)) - return; - - if (G_LIKELY(gc->ic != NULL)) { - fata = gc->ic->proto_data; - fata->gcs = g_slist_remove(fata->gcs, gc); - } - - imcb_chat_free(gc); -} - -/** - * Implements #prpl->init(). This initializes an account. - * - * @param acc The #account. - **/ -static void fb_init(account_t *acc) +static void +fb_init(account_t *acct) { set_t *s; - s = set_add(&acc->set, "cid", NULL, NULL, acc); + s = set_add(&acct->set, "cid", NULL, NULL, acct); s->flags = SET_NULL_OK | SET_HIDDEN; - s = set_add(&acc->set, "cuid", NULL, NULL, acc); + s = set_add(&acct->set, "did", NULL, NULL, acct); s->flags = SET_NULL_OK | SET_HIDDEN; - s = set_add(&acc->set, "mid", NULL, NULL, acc); + s = set_add(&acct->set, "mid", NULL, NULL, acct); s->flags = SET_NULL_OK | SET_HIDDEN; - s = set_add(&acc->set, "token", NULL, NULL, acc); + s = set_add(&acct->set, "token", NULL, NULL, acct); s->flags = SET_NULL_OK | SET_HIDDEN | SET_PASSWORD; - s = set_add(&acc->set, "stoken", NULL, NULL, acc); + s = set_add(&acct->set, "stoken", NULL, NULL, acct); s->flags = SET_NULL_OK | SET_HIDDEN; - s = set_add(&acc->set, "uid", NULL, NULL, acc); + s = set_add(&acct->set, "uid", NULL, NULL, acct); s->flags = SET_NULL_OK | SET_HIDDEN; + + set_add(&acct->set, "mark_read", "true", set_eval_bool, acct); + set_add(&acct->set, "show_unread", "true", set_eval_bool, acct); + set_add(&acct->set, "sync_interval", "30", set_eval_int, acct); } -/** - * Implements #prpl->login(). This logins an account in. - * - * @param acc The #account. - **/ -static void fb_login(account_t *acc) +static void +fb_login(account_t *acc) { - fb_data_t *fata; + FbApi *api; + FbData *fata; + struct im_connection *ic; fata = fb_data_new(acc); - imcb_log(fata->ic, "Connecting"); - - if (fata->api->token == NULL) { - imcb_log(fata->ic, "Requesting authentication token"); - fb_api_auth(fata->api, acc->user, acc->pass); + api = fb_data_get_api(fata); + ic = fb_data_get_connection(fata); + ic->proto_data = fata; + + g_signal_connect(api, + "auth", + G_CALLBACK(fb_cb_api_auth), + fata); + g_signal_connect(api, + "connect", + G_CALLBACK(fb_cb_api_connect), + fata); + g_signal_connect(api, + "contact", + G_CALLBACK(fb_cb_api_contact), + fata); + g_signal_connect(api, + "contacts", + G_CALLBACK(fb_cb_api_contacts), + fata); + g_signal_connect(api, + "error", + G_CALLBACK(fb_cb_api_error), + fata); + g_signal_connect(api, + "events", + G_CALLBACK(fb_cb_api_events), + fata); + g_signal_connect(api, + "messages", + G_CALLBACK(fb_cb_api_messages), + fata); + g_signal_connect(api, + "presences", + G_CALLBACK(fb_cb_api_presences), + fata); + g_signal_connect(api, + "thread", + G_CALLBACK(fb_cb_api_thread), + fata); + g_signal_connect(api, + "thread-create", + G_CALLBACK(fb_cb_api_thread_create), + fata); + g_signal_connect(api, + "threads", + G_CALLBACK(fb_cb_api_threads), + fata); + g_signal_connect(api, + "typing", + G_CALLBACK(fb_cb_api_typing), + fata); + + if (!fb_data_load(fata)) { + imcb_log(ic, "Authenticating"); + fb_api_auth(api, acc->user, acc->pass); return; } - imcb_log(fata->ic, "Fetching contacts"); - fb_api_contacts(fata->api); + imcb_log(ic, "Fetching contacts"); + fb_api_contacts(api); } -/** - * Implements #prpl->logout(). This logs an account out. - * - * @param ic The #im_connection. - **/ -static void fb_logout(struct im_connection *ic) +static void +fb_logout(struct im_connection *ic) { - fb_data_t *fata = ic->proto_data; + FbApi *api; + FbData *fata = ic->proto_data; - if (fata->api->stoken == NULL) { - set_reset(&ic->acc->set, "stoken"); - } + api = fb_data_get_api(fata); + ic->proto_data = NULL; - fb_api_disconnect(fata->api); - fb_data_free(fata); + fb_data_save(fata); + fb_api_disconnect(api); + g_object_unref(fata); } -/** - * Implements #prpl->buddy_msg(). This sends a message to a buddy. - * - * @param ic The #im_connection. - * @param to The handle of the buddy. - * @param message The message to send. - * @param flags The message flags. (Irrelevant to this plugin) - * - * @return 0. (Upstream bitlbee does nothing with this) - **/ -static int fb_buddy_msg(struct im_connection *ic, char *to, char *message, - int flags) +static int +fb_buddy_msg(struct im_connection *ic, char *to, char *message, int flags) { - fb_data_t *fata = ic->proto_data; - fb_id_t uid; + FbApi *api; + FbData *fata = ic->proto_data; + FbId uid; + api = fb_data_get_api(fata); uid = FB_ID_FROM_STR(to); - fb_api_message(fata->api, uid, FALSE, message); + fb_api_message(api, uid, FALSE, message); return 0; } -/** - * Implements #prpl->send_typing(). This sends the typing state message. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - * @param flags The message flags. (Irrelevant to this plugin) - * - * @return 0. (Upstream bitlbe does nothing with this) - **/ -static int fb_send_typing(struct im_connection *ic, char *who, int flags) +static int +fb_send_typing(struct im_connection *ic, char *who, int flags) { - fb_data_t *fata = ic->proto_data; - fb_id_t uid; - gboolean state; + FbApi *api; + FbData *fata = ic->proto_data; + FbId uid; + gboolean state; - uid = FB_ID_FROM_STR(who); + api = fb_data_get_api(fata); + uid = FB_ID_FROM_STR(who); state = (flags & OPT_TYPING) != 0; - fb_api_typing(fata->api, uid, state); + fb_api_typing(api, uid, state); return 0; } -/** - * Implements #prpl->add_buddy(). This adds a buddy. - * - * @param ic The #im_connection. - * @param name The name of the buddy to add. - * @param group The group of the buddy. (Irrelevant to this plugin) - **/ -static void fb_add_buddy(struct im_connection *ic, char *name, char *group) +static void +fb_add_buddy(struct im_connection *ic, char *name, char *group) { } -/** - * Implements #prpl->remove_buddy(). This removes a buddy. - * - * @param ic The #im_connection. - * @param name The name of the buddy to add. - * @param group The group of the buddy. (Irrelevant to this plugin) - **/ -static void fb_remove_buddy(struct im_connection *ic, char *name, char *group) +static void +fb_remove_buddy(struct im_connection *ic, char *name, char *group) { } -/** - * Implements #prpl->add_permit(). This is not used by the plugin. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_add_permit(struct im_connection *ic, char *who) +static void +fb_chat_invite(struct groupchat *gc, char *who, char *message) { + FbApi *api; + FbData *fata = gc->ic->proto_data; + FbId tid; + FbId uid; -} - -/** - * Implements #prpl->add_deny(). This blocks a buddy. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_add_deny(struct im_connection *ic, char *who) -{ - -} - -/** - * Implements #prpl->rem_permit(). This is not used by the plugin. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_rem_permit(struct im_connection *ic, char *who) -{ - -} - -/** - * Implements #prpl->rem_deny(). This unblocks a buddy. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_rem_deny(struct im_connection *ic, char *who) -{ - -} - -/** - * Implements #prpl->get_info(). This retrieves the info of a buddy. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_get_info(struct im_connection *ic, char *who) -{ - -} - -/** - * Implements #prpl->chat_invite(). This invites a user to a #groupchat. - * - * @param gc The #groupchat. - * @param who Ignored. - * @param message The handle to invite. - **/ -void fb_chat_invite(struct groupchat *gc, char *who, char *message) -{ - fb_data_t *fata = gc->ic->proto_data; - fb_id_t tid; - fb_id_t uid; - + api = fb_data_get_api(fata); tid = FB_ID_FROM_STR(gc->title); uid = FB_ID_FROM_STR(who); - fb_api_thread_invite(fata->api, tid, uid); + + fb_api_thread_invite(api, tid, uid); imcb_chat_add_buddy(gc, who); } -/** - * Implements #prpl->chat_leave(). This leaves a #groupchat. - * - * @param gc The #groupchat. - **/ -void fb_chat_leave(struct groupchat *gc) +static void +fb_chat_leave(struct groupchat *gc) { - fb_data_groupchat_free(gc); + FbData *fata = gc->ic->proto_data; + + fb_data_remove_groupchat(fata, gc); + imcb_chat_free(gc); } -/** - * Implements #prpl->chat_msg(). This sends a message to a #groupchat. - * - * @param gc The #groupchat. - * @param message The message to send. - * @param flags Ignored. - **/ -void fb_chat_msg(struct groupchat *gc, char *message, int flags) +static void +fb_chat_msg(struct groupchat *gc, char *message, int flags) { - fb_data_t *fata = gc->ic->proto_data; - fb_id_t tid; + FbApi *api; + FbData *fata = gc->ic->proto_data; + FbId tid; + api = fb_data_get_api(fata); tid = FB_ID_FROM_STR(gc->title); - fb_api_message(fata->api, tid, TRUE, message); + fb_api_message(api, tid, TRUE, message); } -/** - * Implements #prpl->chat_join(). This joins a #groupchat. - * - * @param ic The #im_connection. - * @param room The room name. - * @param nick The nick name. - * @param password The password. - * @param sets The #set array. - **/ -struct groupchat *fb_chat_join(struct im_connection *ic, const char *room, - const char *nick, const char *password, - set_t **sets) +static struct groupchat * +fb_chat_join(struct im_connection *ic, const char *room, const char *nick, + const char *password, set_t **sets) { - fb_data_t *fata = ic->proto_data; - fb_id_t tid; + FbId tid; struct groupchat *gc; tid = FB_ID_FROM_STR(room); - gc = fb_data_groupchat_new(ic, tid, NULL); + gc = fb_data_groupchat_new(ic, tid, NULL); if (gc == NULL) { - imcb_error(fata->ic, "Failed to join chat: %" FB_ID_FORMAT, tid); + imcb_error(ic, "Failed to join chat: %" FB_ID_FORMAT, tid); return NULL; } return gc; } -/** - * Implements #prpl->chat_topic(). This sets a #groupchat topic. - * - * @param gc The #groupchat. - * @param topic The topic - **/ -void fb_chat_topic(struct groupchat *gc, char *topic) +static void +fb_chat_topic(struct groupchat *gc, char *topic) { - fb_data_t *fata = gc->ic->proto_data; - fb_id_t tid; + FbApi *api; + FbData *fata = gc->ic->proto_data; + FbId tid; + api = fb_data_get_api(fata); tid = FB_ID_FROM_STR(gc->title); - fb_api_thread_topic(fata->api, tid, topic); + fb_api_thread_topic(api, tid, topic); imcb_chat_topic(gc, NULL, topic, 0); } -/** - * Implements #prpl->auth_allow(). This accepts buddy requests. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_auth_allow(struct im_connection *ic, const char *who) -{ - -} - -/** - * Implements #prpl->auth_allow(). This denies buddy requests. - * - * @param ic The #im_connection. - * @param who The handle of the buddy. - **/ -static void fb_auth_deny(struct im_connection *ic, const char *who) -{ - -} - -/** - * Implements #prpl->buddy_data_add(). This adds data to the buddy. - * - * @param bu The #bee_user. - **/ -static void fb_buddy_data_add(struct bee_user *bu) -{ - -} - -/** - * Implements #prpl->buddy_data_free(). This frees the buddy data. - * - * @param bu The #bee_user. - **/ -static void fb_buddy_data_free(struct bee_user *bu) -{ - -} - -/** - * Obtains a #account from command arguments. - * - * @param irc The #irc. - * @param args The command arguments. - * @param required The amount of required arguments. - * @param offset The return location for the args offset. - * - * @return The #account or NULL on error. - **/ -static account_t *fb_cmd_account(irc_t *irc, char **args, guint required, - guint *offset) +static account_t * +fb_cmd_account(irc_t *irc, char **args, guint required, guint *offset) { account_t *a; - account_t *acc; - guint accs; - guint size; - guint oset; + account_t *acct; + guint acctc; + guint size; + guint oset; - for (accs = 0, a = irc->b->accounts; a != NULL; a = a->next) { + for (acctc= 0, a = irc->b->accounts; a != NULL; a = a->next) { if ((g_ascii_strcasecmp(a->prpl->name, "facebook") == 0) && (a->ic != NULL)) { - acc = a; - accs++; + acct = a; + acctc++; } } - if (accs == 0) { + if (acctc == 0) { irc_rootmsg(irc, "There are no active Facebook accounts!"); return NULL; } @@ -831,33 +784,33 @@ static account_t *fb_cmd_account(irc_t *irc, char **args, guint required, /* Calculate the size of args */ for (size = 1; args[size] != NULL; size++); - if (accs > 1) { + if (acctc > 1) { if (args[1] == NULL) { irc_rootmsg(irc, "More than one Facebook account, specify one."); return NULL; } /* More than one account, look up by handle */ - acc = account_get(irc->b, args[1]); + acct = account_get(irc->b, args[1]); oset = 2; - if (acc == NULL) { + if (acct == NULL) { irc_rootmsg(irc, "Unknown account: %s", args[1]); return NULL; } - if (acc->ic == NULL) { - irc_rootmsg(irc, "Account not online: %s", acc->tag); + if (acct->ic == NULL) { + irc_rootmsg(irc, "Account not online: %s", acct->tag); return NULL; } - if (g_ascii_strcasecmp(acc->prpl->name, "facebook") != 0) { - irc_rootmsg(irc, "Unknown Facebook account: %s", acc->tag); + if (g_ascii_strcasecmp(acct->prpl->name, "facebook") != 0) { + irc_rootmsg(irc, "Unknown Facebook account: %s", acct->tag); return NULL; } } else if ((size != (required + 1)) && (args[1] != NULL) && - (account_get(irc->b, args[1]) == acc)) + (account_get(irc->b, args[1]) == acct)) { /* One account with an identifier */ oset = 2; @@ -871,149 +824,138 @@ static account_t *fb_cmd_account(irc_t *irc, char **args, guint required, return NULL; } - if (offset != NULL) + if (offset != NULL) { *offset = oset; + } - return acc; + return acct; } -/** - * Implemented #root_command_add() callback for the 'fbchats' command. - * - * @param irc The #irc. - * @param args The command arguments. - **/ -static void fb_cmd_fbchats(irc_t *irc, char **args) +static void +fb_cmd_fbchats(irc_t *irc, char **args) { - account_t *acc; - fb_data_t *fata; + account_t *acct; + FbApi *api; + FbData *fata; - acc = fb_cmd_account(irc, args, 0, NULL); + acct = fb_cmd_account(irc, args, 0, NULL); - if (acc == NULL) + if (acct == NULL) { return; + } - fata = acc->ic->proto_data; - fb_api_thread_list(fata->api, 25); + fata = acct->ic->proto_data; + api = fb_data_get_api(fata); + fb_api_threads(api); } -/** - * Implemented #root_command_add() callback for the 'fbcreate' command. - * - * @param irc The #irc. - * @param args The command arguments. - **/ -static void fb_cmd_fbcreate(irc_t *irc, char **args) +static void +fb_cmd_fbcreate(irc_t *irc, char **args) { - account_t *acc; - fb_data_t *fata; - fb_id_t uid; + account_t *acct; + FbApi *api; + FbData *fata; + FbId *duid; + FbId uid; irc_user_t *iu; - GSList *uids; - guint oset; - guint i; + GSList *uids = NULL; + guint oset; + guint i; + struct im_connection *ic; - acc = fb_cmd_account(irc, args, 2, &oset); - uids = NULL; + acct = fb_cmd_account(irc, args, 2, &oset); - if (acc == NULL) + if (acct == NULL) { return; + } - fata = acc->ic->proto_data; + fata = acct->ic->proto_data; + ic = fb_data_get_connection(fata); for (i = oset; args[i] != NULL; i++) { iu = irc_user_by_name(irc, args[i]); if (iu != NULL) { uid = FB_ID_FROM_STR(iu->bu->handle); - uids = g_slist_prepend(uids, g_memdup(&uid, sizeof uid)); + duid = g_memdup(&uid, sizeof uid); + uids = g_slist_prepend(uids, duid); } } if (uids == NULL) { - imcb_error(fata->ic, "No valid users specified"); + imcb_error(ic, "No valid users specified"); return; } - fb_api_thread_create(fata->api, uids); + api = fb_data_get_api(fata); + fb_api_thread_create(api, uids); g_slist_free_full(uids, g_free); } -/** - * Implemented #root_command_add() callback for the 'fbjoin' command. - * - * @param irc The #irc. - * @param args The command arguments. - **/ -static void fb_cmd_fbjoin(irc_t *irc, char **args) +static void +fb_cmd_fbjoin(irc_t *irc, char **args) { - account_t *acc; - fb_data_t *fata; - fb_id_t *tid; - gchar *name; - guint oset; - gint64 indx; + account_t *acct; + FbData *fata; + FbId tid; + gchar *name; + guint i; + guint oset; + struct im_connection *ic; - acc = fb_cmd_account(irc, args, 2, &oset); + acct = fb_cmd_account(irc, args, 2, &oset); - if (acc == NULL) + if (acct == NULL) { return; + } + + fata = acct->ic->proto_data; + ic = fb_data_get_connection(fata); - fata = acc->ic->proto_data; name = args[oset + 1]; - indx = g_ascii_strtoll(args[oset], NULL, 10); - tid = g_slist_nth_data(fata->tids, indx - 1); + i = g_ascii_strtoll(args[oset], NULL, 10); + tid = fb_data_get_thread(fata, i - 1); - if ((indx < 1) || (tid == NULL)) { - imcb_error(fata->ic, "Invalid index: %" G_GINT64_FORMAT, indx); + if ((i < 1) || (tid == 0)) { + imcb_error(ic, "Invalid index: %u", i); return; } - if (fb_data_groupchat_new(acc->ic, *tid, name) == NULL) { - imcb_error(fata->ic, "Failed to join chat: %s (%" FB_ID_FORMAT ")", - name, *tid); + if (fb_data_groupchat_new(ic, tid, name) == NULL) { + imcb_error(ic, "Failed to join chat: %s (%" FB_ID_FORMAT ")", + name, tid); } } -/** - * Implements the #init_plugin() function. BitlBee looks for this - * function and executes it to register the protocol and its related - * callbacks. - **/ -void init_plugin() -{ - struct prpl *pp; - - pp = g_new0(struct prpl, 1); - - pp->name = "facebook"; - pp->options = OPT_NOOTR; - pp->init = fb_init; - pp->login = fb_login; - pp->logout = fb_logout; - pp->buddy_msg = fb_buddy_msg; - pp->send_typing = fb_send_typing; - pp->add_buddy = fb_add_buddy; - pp->remove_buddy = fb_remove_buddy; - pp->add_permit = fb_add_permit; - pp->add_deny = fb_add_deny; - pp->rem_permit = fb_rem_permit; - pp->rem_deny = fb_rem_deny; - pp->get_info = fb_get_info; - pp->chat_invite = fb_chat_invite; - pp->chat_leave = fb_chat_leave; - pp->chat_msg = fb_chat_msg; - pp->chat_join = fb_chat_join; - pp->chat_topic = fb_chat_topic; - pp->handle_cmp = g_ascii_strcasecmp; - pp->auth_allow = fb_auth_allow; - pp->auth_deny = fb_auth_deny; - pp->buddy_data_add = fb_buddy_data_add; - pp->buddy_data_free = fb_buddy_data_free; - - register_protocol(pp); - - root_command_add("fbchats", 0, fb_cmd_fbchats, 0); +G_MODULE_EXPORT void +init_plugin(void); + +G_MODULE_EXPORT void +init_plugin(void) +{ + struct prpl *dpp; + + static const struct prpl pp = { + .name = "facebook", + .init = fb_init, + .login = fb_login, + .logout = fb_logout, + .buddy_msg = fb_buddy_msg, + .send_typing = fb_send_typing, + .add_buddy = fb_add_buddy, + .remove_buddy = fb_remove_buddy, + .chat_invite = fb_chat_invite, + .chat_leave = fb_chat_leave, + .chat_msg = fb_chat_msg, + .chat_join = fb_chat_join, + .chat_topic = fb_chat_topic, + .handle_cmp = g_strcmp0 + }; + + dpp = g_memdup(&pp, sizeof pp); + register_protocol(dpp); + + root_command_add("fbchats", 0, fb_cmd_fbchats, 0); root_command_add("fbcreate", 0, fb_cmd_fbcreate, 0); - root_command_add("fbjoin", 0, fb_cmd_fbjoin, 0); + root_command_add("fbjoin", 0, fb_cmd_fbjoin, 0); } |