aboutsummaryrefslogblamecommitdiffstats
path: root/matrix-sync.c
blob: b86238e43470bfb59824e42833cc1a3df53b4541 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   
                                        












                                                                       
                                                                               




















                                     
                          


                      
                                                                              
                        














                                                                      

                               













                                                                              




                                                                          
 





                                                                                
                                                     
 
                                                               







                                                                 
                                                        











                                                                              
                                                                    






                                                           
                                                                        








                                            
                                                                        































                                                                              
                                                                           

                                                                       


                                                             
                                                                              
                   
 
                                                                    
                                                          




                                 
                                                     
 
                           
                                                                       
                                                           

                                                                   
 
/**
 * matrix-sync.c: Handle the 'sync' loop
 *
 * 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-sync.h"

/* json-glib */
#include <json-glib/json-glib.h>

/* libpurple */
#include "connection.h"
#include "conversation.h"
#include "debug.h"

/* libmatrix */
#include "matrix-api.h"
#include "matrix-json.h"
#include "matrix-room.h"


typedef struct _RoomEventParserData {
    PurpleConversation *conv;
    JsonObject *event_map;
    gboolean state_events;
} RoomEventParserData;


static void matrix_sync_complete(MatrixConnectionData *ma, gpointer user_data,
        JsonNode *body);

/**
 * handle an event for a room
 *
 * @param state        the complete state array (unused)
 * @param state_id     position within the array (unused)
 * @param state_entry  the event id to be handled
 * @param user_data    a RoomEventParserData
 */
static void _parse_room_event(JsonArray *event_array, guint event_idx,
        JsonNode *event, gpointer user_data)
{
    RoomEventParserData *data = user_data;
    PurpleConversation *conv = data->conv;
    JsonObject *event_map = data->event_map;
    JsonObject *json_event_obj;
    const gchar *event_id;

    event_id = matrix_json_node_get_string(event);
    if(event_id == NULL) {
        purple_debug_warning("prplmatrix", "non-string event_id");
        return;
    }

    json_event_obj = matrix_json_object_get_object_member(
            event_map, event_id);
    if(json_event_obj == NULL) {
        purple_debug_warning("prplmatrix", "unknown event_id %s\n", event_id);
        return;
    }

    if(data->state_events)
        matrix_room_update_state_table(conv, event_id, json_event_obj);
    else
        matrix_room_handle_timeline_event(conv, event_id, json_event_obj);


}

/**
 * parse the list of events in a sync response
 */
static void _parse_room_event_array(PurpleConversation *conv, JsonArray *events,
        JsonObject* event_map, gboolean state_events)
{
    RoomEventParserData data = {conv, event_map, state_events};
    json_array_foreach_element(events, _parse_room_event, &data);
}


/**
 * handle a room within the sync response
 */
static void matrix_sync_room(const gchar *room_id,
        JsonObject *room_data, MatrixConnectionData *ma)
{
    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);

    /* parse the room state */
    state_object = matrix_json_object_get_object_member(room_data, "state");
    state_array = matrix_json_object_get_array_member(state_object, "events");
    if(state_array != NULL)
        _parse_room_event_array(conv, state_array, event_map, TRUE);

    /* parse the timeline events */
    timeline_object = matrix_json_object_get_object_member(
                room_data, "timeline");
    timeline_array = matrix_json_object_get_array_member(
                timeline_object, "events");
    if(timeline_array != NULL)
        _parse_room_event_array(conv, timeline_array, event_map, FALSE);

    /* ensure the buddy list is up to date*/
    matrix_room_update_buddy_list(conv);
}


/**
 * handle the results of the sync request
 */
static void matrix_handle_sync(MatrixConnectionData *ma, JsonNode *body)
{
    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");
    joined_rooms = matrix_json_object_get_object_member(rooms, "joined");

    if(joined_rooms == NULL) {
        purple_debug_warning("matrixprpl", "didn't find joined rooms list\n");
        return;
    }

    room_ids = json_object_get_members(joined_rooms);
    for(elem = room_ids; elem; elem = elem->next) {
        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);
    }
    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);
}


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);
}