From caff31061b68f3b26a889931503a61bf12b76329 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 22 Oct 2015 17:08:58 +0100 Subject: Refactor the connection code Move all matrix-login and bits of matrix-sync into matrix-connection, where it seems to make more sense. Also move MatrixConnectionData into matrix-connection.h --- Makefile | 3 +- libmatrix.c | 28 +++++++--- libmatrix.h | 6 --- matrix-api.c | 2 + matrix-api.h | 2 +- matrix-connection.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++ matrix-connection.h | 57 +++++++++++++++++++++ matrix-login.c | 72 -------------------------- matrix-login.h | 29 ----------- matrix-room.c | 3 +- matrix-room.h | 3 +- matrix-sync.c | 44 +++------------- matrix-sync.h | 24 +++++---- 13 files changed, 250 insertions(+), 168 deletions(-) create mode 100644 matrix-connection.c create mode 100644 matrix-connection.h delete mode 100644 matrix-login.c delete mode 100644 matrix-login.h diff --git a/Makefile b/Makefile index 4076d18..5f41767 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ DATA_ROOT_DIR_PURPLE = $(shell $(PKG_CONFIG) --variable=datarootdir purple) # generate .d files when compiling CPPFLAGS+=-MMD -OBJECTS=libmatrix.o matrix-api.o matrix-json.o matrix-login.o matrix-room.o \ +OBJECTS=libmatrix.o matrix-api.o matrix-connection.o matrix-json.o \ + matrix-room.o \ matrix-sync.o TARGET=libmatrix.so diff --git a/libmatrix.c b/libmatrix.c index 6712119..1a2a45f 100644 --- a/libmatrix.c +++ b/libmatrix.c @@ -45,7 +45,7 @@ #include "util.h" #include "version.h" -#include "matrix-login.h" +#include "matrix-connection.h" #include "matrix-room.h" /** @@ -62,6 +62,26 @@ static const char *matrixprpl_list_icon(PurpleAccount *acct, PurpleBuddy *buddy) return "matrix"; } +/** + * Start the connection to a matrix account + */ +void matrixprpl_login(PurpleAccount *acct) +{ + PurpleConnection *pc = purple_account_get_connection(acct); + matrix_connection_new(pc); + matrix_connection_start_login(pc); +} + + +/** + * Called to handle closing the connection to an account + */ +static void matrixprpl_close(PurpleConnection *pc) +{ + matrix_connection_free(pc); +} + + /* Get the list of information we need to add a chat to our buddy list */ static GList *matrixprpl_chat_info(PurpleConnection *gc) { @@ -396,12 +416,6 @@ static GList *matrixprpl_blist_node_menu(PurpleBlistNode *node) { } } -static void matrixprpl_close(PurpleConnection *gc) -{ - /* notify other matrixprpl accounts */ - foreach_matrixprpl_gc(report_status_change, gc, NULL); -} - static int matrixprpl_send_im(PurpleConnection *gc, const char *who, const char *message, PurpleMessageFlags flags) { diff --git a/libmatrix.h b/libmatrix.h index 38063d6..e485512 100644 --- a/libmatrix.h +++ b/libmatrix.h @@ -50,10 +50,4 @@ /* identifiers for the chat info / "components" */ #define PRPL_CHAT_INFO_ROOM_ID "room_id" -typedef struct _MatrixConnectionData { - struct _PurpleConnection *pc; - gchar *homeserver; /* hostname (:port) of the homeserver */ - gchar *access_token; /* access token corresponding to our user */ -} MatrixConnectionData; - #endif diff --git a/matrix-api.c b/matrix-api.c index 92ae55b..a9c5227 100644 --- a/matrix-api.c +++ b/matrix-api.c @@ -450,6 +450,8 @@ MatrixApiRequestData *matrix_api_password_login(MatrixConnectionData *conn, if(purple_debug_is_unsafe()) purple_debug_info("matrixprpl", "request %s\n", request->str); + else + purple_debug_info("matrixprpl", "logging in %s\n", username); fetch_data = matrix_api_start(url, request->str, conn, callback, NULL, NULL, user_data, 0); diff --git a/matrix-api.h b/matrix-api.h index 8e09b70..4394564 100644 --- a/matrix-api.h +++ b/matrix-api.h @@ -33,7 +33,7 @@ /* libpurple */ #include "util.h" -#include "libmatrix.h" +#include "matrix-connection.h" struct _JsonNode; struct _JsonObject; diff --git a/matrix-connection.c b/matrix-connection.c new file mode 100644 index 0000000..7eb57b3 --- /dev/null +++ b/matrix-connection.c @@ -0,0 +1,145 @@ +/** + * Implementation of the matrix login process + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "matrix-connection.h" + +#include + +/* json-glib */ +#include + +/* libpurple */ +#include + +/* libmatrix */ +#include "libmatrix.h" +#include "matrix-api.h" +#include "matrix-json.h" +#include "matrix-sync.h" + +static void _start_next_sync(MatrixConnectionData *ma, + const gchar *next_batch, int timeout); + + +void matrix_connection_new(PurpleConnection *pc) +{ + MatrixConnectionData *conn; + + g_assert(purple_connection_get_protocol_data(pc) == NULL); + conn = g_new0(MatrixConnectionData, 1); + conn->pc = pc; + purple_connection_set_protocol_data(pc, conn); +} + + +void matrix_connection_free(PurpleConnection *pc) +{ + MatrixConnectionData *conn = purple_connection_get_protocol_data(pc); + + g_assert(conn != NULL); + + purple_connection_set_protocol_data(pc, NULL); + + g_free(conn->homeserver); + conn->homeserver = NULL; + + g_free(conn->access_token); + conn->access_token = NULL; + + conn->pc = NULL; + + g_free(conn); +} + + +/* callback which is called when a /sync request completes */ +static void _sync_complete(MatrixConnectionData *ma, gpointer user_data, + JsonNode *body) +{ + PurpleConnection *pc = ma->pc; + const gchar *next_batch; + + purple_connection_update_progress(pc, _("Connected"), 2, 3); + purple_connection_set_state(pc, PURPLE_CONNECTED); + + matrix_sync_parse(pc, body, &next_batch); + + /* Start the next sync */ + if(next_batch == NULL) { + purple_connection_error_reason(pc, + PURPLE_CONNECTION_ERROR_OTHER_ERROR, "No next_batch field"); + return; + } + purple_account_set_string(pc->account, PRPL_ACCOUNT_OPT_NEXT_BATCH, + next_batch); + + _start_next_sync(ma, next_batch, 30000); +} + + +static void _start_next_sync(MatrixConnectionData *ma, + const gchar *next_batch, int timeout) +{ + matrix_api_sync(ma, next_batch, timeout, _sync_complete, NULL); +} + +static void _login_completed(MatrixConnectionData *conn, + gpointer user_data, + JsonNode *json_root) +{ + PurpleConnection *pc = conn->pc; + JsonObject *root_obj; + const gchar *access_token; + const gchar *next_batch; + + root_obj = matrix_json_node_get_object(json_root); + access_token = matrix_json_object_get_string_member(root_obj, + "access_token"); + if(access_token == NULL) { + purple_connection_error_reason(pc, + PURPLE_CONNECTION_ERROR_OTHER_ERROR, + "No access_token in /login response"); + return; + } + conn->access_token = g_strdup(access_token); + + /* start the sync loop */ + next_batch = purple_account_get_string(pc->account, + PRPL_ACCOUNT_OPT_NEXT_BATCH, NULL); + + purple_connection_update_progress(pc, _("Initial Sync"), 1, 3); + _start_next_sync(conn, next_batch, 0); + +} + + +void matrix_connection_start_login(PurpleConnection *pc) +{ + PurpleAccount *acct = pc->account; + MatrixConnectionData *conn = purple_connection_get_protocol_data(pc); + + conn->homeserver = g_strdup(purple_account_get_string(pc->account, + PRPL_ACCOUNT_OPT_HOME_SERVER, DEFAULT_HOME_SERVER)); + + purple_connection_set_state(pc, PURPLE_CONNECTING); + purple_connection_update_progress(pc, _("Logging in"), 0, 3); + + matrix_api_password_login(conn, acct->username, + purple_account_get_password(acct), _login_completed, conn); +} + diff --git a/matrix-connection.h b/matrix-connection.h new file mode 100644 index 0000000..aaea528 --- /dev/null +++ b/matrix-connection.h @@ -0,0 +1,57 @@ +/** + * matrix-connection.h: handle the connection to a matrix homeserver + * + * When matrix_connection_start_login is called, we first get an access + * token by calling /login. We then repeatedly poll the /sync API endpoint. + * Each time /sync returns, the returned events are dispatched to the + * relevant rooms, and another /sync request is started. + * + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef MATRIX_CONNECTION_H +#define MATRIX_CONNECTION_H + +#include + +struct _PurpleConnection; + +typedef struct _MatrixConnectionData { + struct _PurpleConnection *pc; + gchar *homeserver; /* hostname (:port) of the homeserver */ + gchar *access_token; /* access token corresponding to our user */ +} MatrixConnectionData; + + +/** + * Allocate a new MatrixConnectionData for the given PurpleConnection + */ +void matrix_connection_new(struct _PurpleConnection *pc); + +/** + * Start the login process on a matrix connection. When this completes, it + * will start the /sync loop + */ +void matrix_connection_start_login(struct _PurpleConnection *pc); + +/** + * free the resources associated with a PurpleConnection + */ +void matrix_connection_free(struct _PurpleConnection *pc); + + +#endif diff --git a/matrix-login.c b/matrix-login.c deleted file mode 100644 index 2d8bc5c..0000000 --- a/matrix-login.c +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Implementation of the matrix login process - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "matrix-login.h" - -#include - -/* json-glib */ -#include - -/* libpurple */ -#include - -/* libmatrix */ -#include "matrix-api.h" -#include "matrix-json.h" -#include "matrix-sync.h" - -static void _login_completed(MatrixConnectionData *conn, - gpointer user_data, - JsonNode *json_root) -{ - JsonObject *root_obj; - const gchar *access_token; - - root_obj = matrix_json_node_get_object(json_root); - access_token = matrix_json_object_get_string_member(root_obj, "access_token"); - if(access_token == NULL) { - purple_connection_error_reason(conn->pc, - PURPLE_CONNECTION_ERROR_OTHER_ERROR, - "No access_token in /login response"); - return; - } - conn->access_token = g_strdup(access_token); /* TODO: free */ - matrix_sync_start_loop(conn); -} - - -void matrixprpl_login(PurpleAccount *acct) -{ - PurpleConnection *pc = purple_account_get_connection(acct); - MatrixConnectionData *ma = g_new0(MatrixConnectionData, 1); /* TODO: free */ - - purple_connection_set_protocol_data(pc, ma); - ma->pc = pc; - - purple_connection_set_state(ma->pc, PURPLE_CONNECTING); - purple_connection_update_progress(ma->pc, _("Logging in"), 0, 3); - - purple_debug_info("matrixprpl", "logging in %s\n", acct->username); - - ma->homeserver = g_strdup(purple_account_get_string( - acct, PRPL_ACCOUNT_OPT_HOME_SERVER, DEFAULT_HOME_SERVER)); - - matrix_api_password_login(ma, acct->username, - purple_account_get_password(acct), _login_completed, ma); -} diff --git a/matrix-login.h b/matrix-login.h deleted file mode 100644 index c3057fb..0000000 --- a/matrix-login.h +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Implementation of the matrix login process - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef MATRIX_LOGIN_H -#define MATRIX_LOGIN_H - -#include "account.h" - -/** - * Set off the login process - */ -void matrixprpl_login(PurpleAccount *acct); - -#endif diff --git a/matrix-room.c b/matrix-room.c index cace33f..872eaa7 100644 --- a/matrix-room.c +++ b/matrix-room.c @@ -404,9 +404,8 @@ void matrix_room_handle_timeline_event(PurpleConversation *conv, PurpleConversation *matrix_room_get_or_create_conversation( - MatrixConnectionData *ma, const gchar *room_id) + PurpleConnection *pc, const gchar *room_id) { - PurpleConnection *pc = ma->pc; PurpleConversation *conv = purple_find_conversation_with_account( PURPLE_CONV_TYPE_CHAT, room_id, pc->account); MatrixRoomStateEventTable *state_table; diff --git a/matrix-room.h b/matrix-room.h index 56a35bf..b454653 100644 --- a/matrix-room.h +++ b/matrix-room.h @@ -33,6 +33,7 @@ #include "libmatrix.h" struct _PurpleConversation; +struct _PurpleConnection; /** * Ensure the room is up to date in the buddy list (ie, it is present, @@ -48,7 +49,7 @@ void matrix_room_update_buddy_list(struct _PurpleConversation *conv); * @param ma account associated with the chat */ struct _PurpleConversation *matrix_room_get_or_create_conversation( - MatrixConnectionData *ma, const gchar *room_id); + struct _PurpleConnection *pc, const gchar *room_id); /** * Leave a chat: notify the server that we are leaving, and (ultimately) diff --git a/matrix-sync.c b/matrix-sync.c index b86238e..5386917 100644 --- a/matrix-sync.c +++ b/matrix-sync.c @@ -27,7 +27,6 @@ #include "debug.h" /* libmatrix */ -#include "matrix-api.h" #include "matrix-json.h" #include "matrix-room.h" @@ -39,9 +38,6 @@ typedef struct _RoomEventParserData { } RoomEventParserData; -static void matrix_sync_complete(MatrixConnectionData *ma, gpointer user_data, - JsonNode *body); - /** * handle an event for a room * @@ -95,14 +91,14 @@ static void _parse_room_event_array(PurpleConversation *conv, JsonArray *events, * handle a room within the sync response */ static void matrix_sync_room(const gchar *room_id, - JsonObject *room_data, MatrixConnectionData *ma) + JsonObject *room_data, PurpleConnection *pc) { JsonObject *state_object, *timeline_object, *event_map; JsonArray *state_array, *timeline_array; PurpleConversation *conv; event_map = matrix_json_object_get_object_member(room_data, "event_map"); - conv = matrix_room_get_or_create_conversation(ma, room_id); + conv = matrix_room_get_or_create_conversation(pc, room_id); /* parse the room state */ state_object = matrix_json_object_get_object_member(room_data, "state"); @@ -126,13 +122,13 @@ static void matrix_sync_room(const gchar *room_id, /** * handle the results of the sync request */ -static void matrix_handle_sync(MatrixConnectionData *ma, JsonNode *body) +void matrix_sync_parse(PurpleConnection *pc, JsonNode *body, + const gchar **next_batch) { JsonObject *rootObj; JsonObject *rooms; JsonObject *joined_rooms; GList *room_ids, *elem; - const gchar *next_batch; rootObj = matrix_json_node_get_object(body); rooms = matrix_json_object_get_object_member(rootObj, "rooms"); @@ -148,38 +144,10 @@ static void matrix_handle_sync(MatrixConnectionData *ma, JsonNode *body) const gchar *room_id = elem->data; JsonObject *room_data = matrix_json_object_get_object_member( joined_rooms, room_id); - matrix_sync_room(room_id, room_data, ma); + matrix_sync_room(room_id, room_data, pc); } g_list_free(room_ids); - /* Start the next sync */ - next_batch = matrix_json_object_get_string_member(rootObj, "next_batch"); - if(next_batch == NULL) { - purple_connection_error_reason(ma->pc, - PURPLE_CONNECTION_ERROR_OTHER_ERROR, "No next_batch field"); - return; - } - purple_account_set_string(ma->pc->account, PRPL_ACCOUNT_OPT_NEXT_BATCH, - next_batch); - matrix_api_sync(ma, next_batch, 30000, matrix_sync_complete, NULL); -} - -/* callback which is called when a /sync request completes */ -static void matrix_sync_complete(MatrixConnectionData *ma, gpointer user_data, - JsonNode *body) -{ - purple_connection_update_progress(ma->pc, _("Connected"), 2, 3); - purple_connection_set_state(ma->pc, PURPLE_CONNECTED); - - matrix_handle_sync(ma, body); + *next_batch = matrix_json_object_get_string_member(rootObj, "next_batch"); } - -void matrix_sync_start_loop(MatrixConnectionData *ma) -{ - const char *next_batch; - purple_connection_update_progress(ma->pc, _("Initial Sync"), 1, 3); - next_batch = purple_account_get_string(ma->pc->account, - PRPL_ACCOUNT_OPT_NEXT_BATCH, NULL); - matrix_api_sync(ma, next_batch, 0, matrix_sync_complete, NULL); -} diff --git a/matrix-sync.h b/matrix-sync.h index 4f267dc..70361c1 100644 --- a/matrix-sync.h +++ b/matrix-sync.h @@ -1,13 +1,6 @@ /** * matrix-sync.h * - * Receipt of events from the matrix homeserver works by continually polling the - * /sync API endpoint. This module manages that process. It provides a single - * method which initiates a /sync request for an authenticated MatrixConnectionData. - * - * On completion of the request, any events it returned are dispatched to the - * relevant rooms, and another /sync request is started. - * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,12 +20,21 @@ #ifndef MATRIX_SYNC_H_ #define MATRIX_SYNC_H_ -#include "libmatrix.h" +#include + +struct _PurpleConnection; +struct _JsonNode; /** - * Start the sync loop for a matrix account. This will repeatedly call - * '/sync' to get room information and new events. + * Parse and dispatch the results of a /sync call. + * + * @param pc Connection to which these results relate + * @param body Body of /sync response + * @param next_batch Returns a pointer to the next_batch setting, for the next + * sync (or NULL if none was found) */ -void matrix_sync_start_loop(MatrixConnectionData *ma); +void matrix_sync_parse(struct _PurpleConnection *pc, struct _JsonNode *body, + const gchar **next_batch); + #endif /* MATRIX_SYNC_H_ */ -- cgit