Skip to content

Commit

Permalink
Join by alias
Browse files Browse the repository at this point in the history
This works, however:

When joining an existing room by alias, only the internal room name
is listed at the top of the pidgin UI.  A followup patch may be
needed to grab the actual room name and display in pidgin.

Signed-off-by: Damien Zammit <[email protected]>
  • Loading branch information
zamaudio committed Jan 19, 2017
1 parent ccf4958 commit a9f2726
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 40 deletions.
47 changes: 38 additions & 9 deletions libmatrix.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "matrix-connection.h"
#include "matrix-room.h"
#include "matrix-api.h"
#include "matrix-json.h"

/**
* Called to get the icon name for the given buddy and account.
Expand All @@ -52,6 +53,27 @@ static const char *matrixprpl_list_icon(PurpleAccount *acct, PurpleBuddy *buddy)
return "matrix";
}

/**
* Callback for join by alias, if it succeeds, join the room
*/
static void room_join_callback(MatrixConnectionData *conn,
gpointer user_data,
struct _JsonNode *json_root,
const char *body,
size_t body_len, const char *content_type)
{
JsonObject *root_obj;
const gchar *room_id;
GHashTable *components = user_data;

if (json_root) {
root_obj = matrix_json_node_get_object(json_root);
room_id = json_object_get_string_member(root_obj, "room_id");
}
if(room_id) {
matrix_connection_join_room(conn->pc, room_id, components);
}
}

/**
* Called to get a list of the PurpleStatusType which are valid for this account
Expand Down Expand Up @@ -139,17 +161,24 @@ static char *matrixprpl_get_chat_name(GHashTable *components)
* Handle a double-click on a chat in the buddy list, or acceptance of a chat
* invite: it is expected that we join the chat.
*/
static void matrixprpl_join_chat(PurpleConnection *gc, GHashTable *components)
static void matrixprpl_join_chat(PurpleConnection *pc, GHashTable *components)
{
const char *room = g_hash_table_lookup(components, PRPL_CHAT_INFO_ROOM_ID);
int chat_id = g_str_hash(room);
PurpleConversation *conv;
const char *room_alias = components ?
g_hash_table_lookup(components, PRPL_CHAT_INFO_ROOM_ID) : "";
int chat_id = room_alias ? g_str_hash(room_alias) : 0;
PurpleConversation *conv = NULL;
PurpleConvChat *chat;
MatrixConnectionData *conn = purple_connection_get_protocol_data(pc);

if (!chat_id) {
return;
}

conv = purple_find_chat(gc, chat_id);
conv = purple_find_chat(pc, chat_id);

if(!conv) {
matrix_connection_join_room(gc, room, components);
if (!conv) {
/* get the room by alias, if possible - join it, otherwise for now, do nothing */
matrix_api_get_roomid_by_alias(conn, room_alias, room_join_callback, NULL, NULL, components);
return;
}

Expand All @@ -162,8 +191,8 @@ static void matrixprpl_join_chat(PurpleConnection *gc, GHashTable *components)
chat = PURPLE_CONV_CHAT(conv);
chat->left = FALSE;

if (!g_slist_find(gc->buddy_chats, conv))
gc->buddy_chats = g_slist_append(gc->buddy_chats, conv);
if (!g_slist_find(pc->buddy_chats, conv))
pc->buddy_chats = g_slist_append(pc->buddy_chats, conv);
purple_conversation_update(conv, PURPLE_CONV_UPDATE_CHATLEFT);
}

Expand Down
52 changes: 40 additions & 12 deletions matrix-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

#include "libmatrix.h"
#include "matrix-json.h"
#include "matrix-room.h"
#include "matrix-connection.h"

struct _MatrixApiRequestData {
PurpleUtilFetchUrlData *purple_data;
Expand Down Expand Up @@ -63,17 +65,19 @@ void matrix_api_error(MatrixConnectionData *conn, gpointer user_data,
void matrix_api_bad_response(MatrixConnectionData *ma, gpointer user_data,
int http_response_code, JsonNode *json_root)
{
JsonObject *json_obj;
JsonObject *json_obj = NULL;
const gchar *errcode = NULL, *error = NULL;
gchar *error_message;

if(json_root != NULL) {
json_obj = matrix_json_node_get_object(json_root);
errcode = matrix_json_object_get_string_member(json_obj, "errcode");
error = matrix_json_object_get_string_member(json_obj, "error");
if (json_obj) {
errcode = matrix_json_object_get_string_member(json_obj, "errcode");
error = matrix_json_object_get_string_member(json_obj, "error");
}
}

if(errcode != NULL && error != NULL) {
if(errcode && error) {
error_message = g_strdup_printf("%s: %s: %s",
_("Error from home server"), errcode, error);
} else {
Expand Down Expand Up @@ -310,8 +314,10 @@ static void matrix_api_complete(PurpleUtilFetchUrlData *url_data,
} else if(response_code >= 300) {
purple_debug_info("matrixprpl", "API gave response %i\n",
response_code);
(data->bad_response_callback)(data->conn, data->user_data,
response_code, root);
if (data && data->conn && data->bad_response_callback) {
(data->bad_response_callback)(data->conn, data->user_data,
response_code, root);
}
} else if (data->callback) {
(data->callback)(data->conn, data->user_data, root,
response_data->body, response_data->body_len,
Expand Down Expand Up @@ -451,7 +457,6 @@ static GString *_build_request(PurpleAccount *acct, const gchar *url,
return request_str;
}


/**
* Start an HTTP call to the API
*
Expand Down Expand Up @@ -538,7 +543,7 @@ static MatrixApiRequestData *matrix_api_start_full(const gchar *url,
/* we couldn't start the request. In this case, our callback will
* already have been called, which will have freed data.
*/
data = NULL;
data->purple_data = NULL;
} else {
data->purple_data = purple_data;
}
Expand Down Expand Up @@ -671,6 +676,30 @@ MatrixApiRequestData *matrix_api_sync(MatrixConnectionData *conn,
}


void matrix_api_get_roomid_by_alias(MatrixConnectionData *conn,
const char *room_alias,
MatrixApiCallback callback,
MatrixApiErrorCallback error_callback,
MatrixApiBadResponseCallback bad_response_callback,
gpointer user_data)
{
GString *url;

url = g_string_new(conn->homeserver);
g_string_append_printf(url, "_matrix/client/r0/directory/room/%s",
purple_url_encode(room_alias));
g_string_append_printf(url, "?access_token=%s",
purple_url_encode(conn->access_token));

purple_debug_info("matrixprpl", "getting room_id from room_alias\n");

matrix_api_start(url->str, "GET", NULL, conn, callback,
error_callback, bad_response_callback,
user_data, -1);

g_string_free(url, TRUE);
}

MatrixApiRequestData *matrix_api_send(MatrixConnectionData *conn,
const gchar *room_id, const gchar *event_type, const gchar *txn_id,
JsonObject *content, MatrixApiCallback callback,
Expand Down Expand Up @@ -770,22 +799,21 @@ MatrixApiRequestData *matrix_api_join_room(MatrixConnectionData *conn,
MatrixApiRequestData *fetch_data;

url = g_string_new(conn->homeserver);
g_string_append(url, "_matrix/client/r0/rooms/");
g_string_append(url, "_matrix/client/r0/join/");
g_string_append(url, purple_url_encode(room));
g_string_append(url, "/join?access_token=");
g_string_append(url, "?access_token=");
g_string_append(url, purple_url_encode(conn->access_token));

purple_debug_info("matrixprpl", "joining %s\n", room);

fetch_data = matrix_api_start(url->str, "POST", "{}", conn, callback,
error_callback, bad_response_callback,
user_data, 0);
user_data, -1);
g_string_free(url, TRUE);

return fetch_data;
}


MatrixApiRequestData *matrix_api_leave_room(MatrixConnectionData *conn,
const gchar *room_id,
MatrixApiCallback callback,
Expand Down
11 changes: 9 additions & 2 deletions matrix-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,15 @@ void matrix_api_bad_response(MatrixConnectionData *ma, gpointer user_data,
int http_response_code, struct _JsonNode *json_root);




/**
* Get roomid by alias
*/
void matrix_api_get_roomid_by_alias(MatrixConnectionData *conn,
const char *room_alias,
MatrixApiCallback callback,
MatrixApiErrorCallback error_callback,
MatrixApiBadResponseCallback bad_response_callback,
gpointer user_data);

/**
* Cancel a call to an API. This will also call the error_callback
Expand Down
43 changes: 26 additions & 17 deletions matrix-connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "matrix-api.h"
#include "matrix-json.h"
#include "matrix-sync.h"
#include "matrix-room.h"

static void _start_next_sync(MatrixConnectionData *ma,
const gchar *next_batch, gboolean full_state);
Expand Down Expand Up @@ -237,22 +238,37 @@ void matrix_connection_start_login(PurpleConnection *pc)
}


static void _join_completed(MatrixConnectionData *conn,
static void _tell_purple_joined_callback(MatrixConnectionData *conn,
gpointer user_data,
JsonNode *json_root,
const char *raw_body, size_t raw_body_len, const char *content_type)
{
GHashTable *components = user_data;
JsonObject *root_obj;
const gchar *room_id;

root_obj = matrix_json_node_get_object(json_root);
room_id = matrix_json_object_get_string_member(root_obj, "room_id");
purple_debug_info("matrixprpl", "join %s completed", room_id);

g_hash_table_destroy(components);
if (room_id && *room_id) {
matrix_room_join_conversation(conn->pc, room_id);
purple_debug_info("matrixprpl", "join %s completed", room_id);
}
}

static void _join_completed(MatrixConnectionData *conn,
gpointer user_data,
JsonNode *json_root,
const char *raw_body, size_t raw_body_len, const char *content_type)
{
JsonObject *root_obj;
const gchar *room_id;

root_obj = matrix_json_node_get_object(json_root);
room_id = matrix_json_object_get_string_member(root_obj, "room_id");
if (room_id && *room_id) {
// Now that we have the actual room id, join it, then create conv!
matrix_api_join_room(conn, room_id, _tell_purple_joined_callback, NULL, NULL, user_data);
}
}

static void _join_error(MatrixConnectionData *conn,
gpointer user_data, const gchar *error_message)
Expand Down Expand Up @@ -287,23 +303,16 @@ static void _join_failed(MatrixConnectionData *conn,
void matrix_connection_join_room(struct _PurpleConnection *pc,
const gchar *room, GHashTable *components)
{
GHashTable *copy;
GHashTableIter iter;
gpointer key, value;
GHashTable *newcomponents;

MatrixConnectionData *conn = purple_connection_get_protocol_data(pc);

/* we have to copy the components table, so that we can pass it back
* later on :/
*/
copy = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_iter_init (&iter, components);
while (g_hash_table_iter_next (&iter, &key, &value)) {
g_hash_table_insert(copy, g_strdup(key), g_strdup(value));
}
/* Assume old components is corrupt */
newcomponents = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
g_hash_table_insert(newcomponents, PRPL_CHAT_INFO_ROOM_ID, g_strdup(room));

matrix_api_join_room(conn, room, _join_completed, _join_error, _join_failed,
copy);
newcomponents);
}


Expand Down
29 changes: 29 additions & 0 deletions matrix-room.c
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,35 @@ void matrix_room_handle_timeline_event(PurpleConversation *conv,
g_free(escaped_body);
}

PurpleConversation *matrix_room_join_conversation(
PurpleConnection *pc, const gchar *room_id)
{
JsonObject *new_state = NULL;
MatrixRoomStateEventTable *state_table;
MatrixRoomMemberTable *member_table;
PurpleConversation *conv;
purple_debug_info("matrixprpl", "Join room %s\n", room_id);

/* tell purple we have joined this chat */
conv = serv_got_joined_chat(pc, g_str_hash(room_id), room_id);

/* create new tables */
state_table = matrix_statetable_new();
member_table = matrix_roommembers_new_table();

/* insert self into member table and update state */
matrix_roommembers_update_member(member_table, pc->account->username, new_state);
matrix_statetable_update(state_table, new_state, NULL, NULL);

/* tell purple about it */
purple_conversation_set_data(conv, PURPLE_CONV_DATA_EVENT_QUEUE, NULL);
purple_conversation_set_data(conv, PURPLE_CONV_DATA_ACTIVE_SEND, NULL);
purple_conversation_set_data(conv, PURPLE_CONV_DATA_STATE, state_table);
purple_conversation_set_data(conv, PURPLE_CONV_MEMBER_TABLE, member_table);

matrix_room_complete_state_update(conv, TRUE);
return conv;
}

PurpleConversation *matrix_room_create_conversation(
PurpleConnection *pc, const gchar *room_id)
Expand Down
5 changes: 5 additions & 0 deletions matrix-room.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ struct _PurpleConnection;
void matrix_room_complete_state_update(struct _PurpleConversation *conv,
gboolean announce_arrivals);

/**
* Join an existing conversation for the given room
*/
struct _PurpleConversation *matrix_room_join_conversation(
struct _PurpleConnection *pc, const gchar *room_id);

/**
* Create a new conversation for the given room
Expand Down

0 comments on commit a9f2726

Please sign in to comment.