aboutsummaryrefslogblamecommitdiffstats
path: root/matrix-login.c
blob: 77300a3b01df0b0afbd206ecddd7298e113bf0ec (plain) (tree)























                                                                                 
                         

                  


                                

                       

                        



                                      






                                                                  
 







































                                                                                        

     

















                                                                                      
    


                                                           
 

                                                                              



























                                                                                 






























                                                                                               
































                                                                       
/**
 * 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 <string.h>

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

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

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

/* TODO: make this configurable */
#define MATRIX_HOMESERVER "matrix.org"

/**
 * handle a room within the initialSync response
 */
static void matrixprpl_handle_initialsync_room(JsonArray *rooms,
                                               guint room_idx,
                                               JsonNode *room,
                                               gpointer user_data)
{
    MatrixAccount *ma = (MatrixAccount *)user_data;
    JsonObject *room_obj;
    JsonArray *state_array;
    const gchar *room_id;
    const gchar *room_name;
    PurpleConversation *conv;
    PurpleChat *chat;
    PurpleGroup *group;
    MatrixRoomStateEventTable *state_table;
    
    /* TODO: error handling */
    room_obj = matrix_json_node_get_object(room);
    room_id = matrix_json_object_get_string_member(room_obj, "room_id");
    state_array = matrix_json_object_get_array_member(room_obj, "state");
    
    purple_debug_info("matrixprpl", "got room %s\n", room_id);

    /* parse the room state */
    state_table = g_hash_table_new(g_str_hash, g_str_equal); /* TODO: free */
    if(state_array != NULL)
    	matrix_room_parse_state_events(state_table, state_array);

    /* todo: distinguish between 1-1 chats and group chats? */

    /* add the room to the buddy list */
    chat = purple_blist_find_chat(ma->pa, room_id);
    if (!chat)
    {
        GHashTable *comp;
        group = purple_find_group("Matrix");
        if (!group)
        {
            group = purple_group_new("Matrix");
            purple_blist_add_group(group, NULL);
        }
        comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); /* TODO:
                                                                              * free? */
        g_hash_table_insert(comp, "room_id", g_strdup(room_id)); /* TODO: free? */
        chat = purple_chat_new(ma->pa, room_id, comp);
        purple_blist_add_chat(chat, group, NULL);
    }

    /* ensure the alias in the buddy list is up-to-date */
    room_name = matrix_room_get_name(state_table);
    purple_blist_alias_chat(chat, room_name);

    /* tell purple we have joined this chat */
    conv = serv_got_joined_chat(ma->pc, g_str_hash(room_id), room_id);
    purple_conversation_set_data(conv, "room_id", g_strdup(room_id)); /* TODO: free */
    purple_conversation_set_data(conv, "state", state_table);
}


/**
 * handle the results of the intialSync request
 */
static void matrixprpl_handle_initialsync(MatrixAccount *ma, JsonNode *body)
{
    JsonObject *rootObj;
    JsonArray *rooms;
    
    /* TODO: error handling */
    rootObj = json_node_get_object(body);
    rooms = json_object_get_array_member(rootObj, "rooms");

    json_array_foreach_element(rooms, matrixprpl_handle_initialsync_room, ma);
    
#if 0
    /* tell purple about everyone on our buddy list who's connected */
    foreach_matrixprpl_gc(discover_status, gc, NULL);

    /* notify other matrixprpl accounts */
    foreach_matrixprpl_gc(report_status_change, gc, NULL);

    /* fetch stored offline messages */
    purple_debug_info("matrixprpl", "checking for offline messages for %s\n",
                      acct->username);
    offline_messages = g_hash_table_lookup(goffline_messages, acct->username);
    while (offline_messages) {
        GOfflineMessage *message = (GOfflineMessage *)offline_messages->data;
        purple_debug_info("matrixprpl", "delivering offline message to %s: %s\n",
                          acct->username, message->message);
        serv_got_im(gc, message->from, message->message, message->flags,
                    message->mtime);
        offline_messages = g_list_next(offline_messages);

        g_free(message->from);
        g_free(message->message);
        g_free(message);
    }

    g_list_free(offline_messages);
    g_hash_table_remove(goffline_messages, &acct->username);
#endif
}


static void matrixprpl_initialsync_complete(MatrixAccount *ma,
                                            gpointer user_data,
                                            int http_response_code,
                                            const gchar *http_response_msg,
                                            const gchar *body_start,
                                            JsonNode *body,
                                            const gchar *error_message)
{
    if (error_message) {
        purple_debug_info("matrixprpl", "initialsync gave error %s\n",
                          error_message);
        purple_connection_error_reason(ma->pc,
            PURPLE_CONNECTION_ERROR_NETWORK_ERROR, error_message);
        return;
    }

    if (http_response_code >= 400) {
        purple_debug_info("matrixprpl", "initialsync gave response %s: %s\n",
                          http_response_msg, body_start);
        purple_connection_error_reason(ma->pc,
                                       PURPLE_CONNECTION_ERROR_OTHER_ERROR, http_response_msg);
        return;
    }

    purple_connection_update_progress(ma->pc, _("Connected"), 2, 3);
    purple_connection_set_state(ma->pc, PURPLE_CONNECTED);

    matrixprpl_handle_initialsync(ma, body);
}
                
/*
 * do the initialsync after login, to get room state
 */
static void matrixprpl_start_initialsync(MatrixAccount *ma)
{
    purple_connection_set_state(ma->pc, PURPLE_CONNECTING);
    purple_connection_update_progress(ma->pc, _("Initial Sync"), 1, 3);
    matrix_initialsync(ma, matrixprpl_initialsync_complete, ma);
}

void matrixprpl_login(PurpleAccount *acct)
{
    PurpleConnection *pc = purple_account_get_connection(acct);
    MatrixAccount *ma = g_new0(MatrixAccount, 1); /* TODO: free */

    purple_connection_set_protocol_data(pc, ma);
    ma->pa = acct;
    ma->pc = pc;
  
    purple_debug_info("matrixprpl", "logging in %s\n", acct->username);

    /* TODO: make this configurable */
    ma->homeserver = g_strdup(MATRIX_HOMESERVER);
    
    /* TODO: use the login API to get our access token.
     *
     * For now, assume that the username *is* the access token.
     */
    ma->access_token = g_strdup(acct->username);

    matrixprpl_start_initialsync(ma);
}