From fac2b2cf665e72f0f7fe66232952401274d51ee7 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sat, 28 Mar 2015 22:51:41 +0000 Subject: [PATCH 1/3] Added check members only room to send mediated invites --- src/muc.c | 14 ++++++++++++++ src/muc.h | 8 ++++++++ src/server_events.c | 3 +++ src/xmpp/message.c | 11 ++++++++++- src/xmpp/stanza.c | 40 ++++++++++++++++++++++++++++++++++++++++ src/xmpp/stanza.h | 2 ++ 6 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/muc.c b/src/muc.c index ea4ae915..1c5e1825 100644 --- a/src/muc.c +++ b/src/muc.c @@ -62,6 +62,7 @@ typedef struct _muc_room_t { Autocomplete jid_ac; GHashTable *nick_changes; gboolean roster_received; + muc_member_type_t member_type; } ChatRoom; GHashTable *rooms = NULL; @@ -177,6 +178,7 @@ muc_join(const char * const room, const char * const nick, new_room->roster_received = FALSE; new_room->pending_nick_change = FALSE; new_room->autojoin = autojoin; + new_room->member_type = MUC_MEMBER_TYPE_UNKNOWN; g_hash_table_insert(rooms, strdup(room), new_room); } @@ -763,6 +765,18 @@ muc_set_affiliation(const char * const room, const char * const affiliation) } } +muc_member_type_t +muc_member_type(const char * const room) +{ + ChatRoom *chat_room = g_hash_table_lookup(rooms, room); + if (chat_room) { + return chat_room->member_type; + } else { + return MUC_MEMBER_TYPE_UNKNOWN; + } +} + + static void _free_room(ChatRoom *room) { diff --git a/src/muc.h b/src/muc.h index 16f217d0..60cf7108 100644 --- a/src/muc.h +++ b/src/muc.h @@ -56,6 +56,12 @@ typedef enum { MUC_AFFILIATION_OWNER } muc_affiliation_t; +typedef enum { + MUC_MEMBER_TYPE_UNKNOWN, + MUC_MEMBER_TYPE_PUBLIC, + MUC_MEMBER_TYPE_MEMBERS_ONLY +} muc_member_type_t; + typedef struct _muc_occupant_t { char *nick; char *jid; @@ -134,4 +140,6 @@ void muc_set_affiliation(const char * const room, const char * const affiliation char *muc_role_str(const char * const room); char *muc_affiliation_str(const char * const room); +muc_member_type_t muc_member_type(const char * const room); + #endif diff --git a/src/server_events.c b/src/server_events.c index a97e0786..f9f5afe4 100644 --- a/src/server_events.c +++ b/src/server_events.c @@ -697,6 +697,9 @@ handle_muc_self_online(const char * const room, const char * const nick, gboolea } else { ui_room_join(room, TRUE); } + + // TODO send disco info request to room + muc_invites_remove(room); muc_roster_set_complete(room); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index e6927f76..1bb3bcdc 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -204,7 +204,16 @@ message_send_invite(const char * const roomjid, const char * const contact, { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *stanza = stanza_create_invite(ctx, roomjid, contact, reason); + xmpp_stanza_t *stanza; + + muc_member_type_t member_type = muc_member_type(roomjid); + if (member_type == MUC_MEMBER_TYPE_PUBLIC) { + log_debug("Sending direct invite to %s, for %s", contact, roomjid); + stanza = stanza_create_invite(ctx, roomjid, contact, reason); + } else { + log_debug("Sending mediated invite to %s, for %s", contact, roomjid); + stanza = stanza_create_mediated_invite(ctx, roomjid, contact, reason); + } xmpp_send(conn, stanza); xmpp_stanza_release(stanza); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 0b291d2e..03567e31 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -440,6 +440,46 @@ stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, return message; } +xmpp_stanza_t * +stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char * const room, + const char * const contact, const char * const reason) +{ + xmpp_stanza_t *message, *x, *invite; + + message = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(message, STANZA_NAME_MESSAGE); + xmpp_stanza_set_attribute(message, STANZA_ATTR_TO, room); + char *id = create_unique_id(NULL); + xmpp_stanza_set_id(message, id); + free(id); + + x = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(x, STANZA_NAME_X); + xmpp_stanza_set_ns(x, STANZA_NS_MUC_USER); + + invite = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(invite, STANZA_NAME_INVITE); + xmpp_stanza_set_attribute(invite, STANZA_ATTR_TO, contact); + + if (reason != NULL) { + xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON); + xmpp_stanza_t *reason_txt = xmpp_stanza_new(ctx); + xmpp_stanza_set_text(reason_txt, reason); + xmpp_stanza_add_child(reason_st, reason_txt); + xmpp_stanza_release(reason_txt); + xmpp_stanza_add_child(invite, reason_st); + xmpp_stanza_release(reason_st); + } + + xmpp_stanza_add_child(x, invite); + xmpp_stanza_release(invite); + xmpp_stanza_add_child(message, x); + xmpp_stanza_release(x); + + return message; +} + xmpp_stanza_t * stanza_create_room_join_presence(xmpp_ctx_t * const ctx, const char * const full_room_jid, const char * const passwd) diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 50f3dbd0..744bd7fb 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -215,6 +215,8 @@ xmpp_stanza_t* stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char * const i xmpp_stanza_t* stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, const char * const contact, const char * const reason); +xmpp_stanza_t* stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char * const room, + const char * const contact, const char * const reason); gboolean stanza_contains_chat_state(xmpp_stanza_t *stanza); From 24a45e5292b1aaf0977d2af801827f5738a6b9c1 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 29 Mar 2015 00:21:18 +0000 Subject: [PATCH 2/3] Set members only property when getting room features --- src/muc.c | 13 +++++++++++++ src/muc.h | 2 ++ src/server_events.c | 2 ++ src/xmpp/iq.c | 9 +++++++-- src/xmpp/xmpp.h | 2 +- tests/xmpp/stub_xmpp.c | 2 +- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/muc.c b/src/muc.c index 1c5e1825..ae48d66b 100644 --- a/src/muc.c +++ b/src/muc.c @@ -210,6 +210,19 @@ muc_set_requires_config(const char * const room, gboolean val) } } +void +muc_set_features(const char * const room, GSList *features) +{ + ChatRoom *chat_room = g_hash_table_lookup(rooms, room); + if (chat_room && features) { + if (g_slist_find_custom(features, "muc_membersonly", (GCompareFunc)g_strcmp0)) { + chat_room->member_type = MUC_MEMBER_TYPE_MEMBERS_ONLY; + } else { + chat_room->member_type = MUC_MEMBER_TYPE_PUBLIC; + } + } +} + /* * Returns TRUE if the user is currently in the room */ diff --git a/src/muc.h b/src/muc.h index 60cf7108..2c7b3e7e 100644 --- a/src/muc.h +++ b/src/muc.h @@ -82,6 +82,8 @@ gboolean muc_autojoin(const char * const room); GList* muc_rooms(void); +void muc_set_features(const char * const room, GSList *features); + char* muc_nick(const char * const room); char* muc_password(const char * const room); diff --git a/src/server_events.c b/src/server_events.c index f9f5afe4..882c308c 100644 --- a/src/server_events.c +++ b/src/server_events.c @@ -164,6 +164,7 @@ handle_disco_info(const char *from, GSList *identities, GSList *features) void handle_room_disco_info(const char * const room, GSList *identities, GSList *features) { + muc_set_features(room, features); ui_show_room_disco_info(room, identities, features); } @@ -699,6 +700,7 @@ handle_muc_self_online(const char * const room, const char * const nick, gboolea } // TODO send disco info request to room + iq_room_info_request(room); muc_invites_remove(room); muc_roster_set_complete(room); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 028c586e..573a50ef 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -178,14 +178,14 @@ iq_disco_info_request(gchar *jid) } void -iq_room_info_request(gchar *room) +iq_room_info_request(const char * const room) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("room_disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, room, NULL); - xmpp_id_handler_add(conn, _disco_info_response_handler, id, room); + xmpp_id_handler_add(conn, _disco_info_response_handler, id, strdup(room)); free(id); @@ -1362,6 +1362,7 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta char *error_message = stanza_get_error_message(stanza); if (room) { handle_room_info_error(room, error_message); + free(room); } else { handle_disco_info_error(from, error_message); } @@ -1422,6 +1423,10 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta g_slist_free_full(features, free); g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); } + + if (room) { + free(room); + } return 1; } diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 7deb71db..af9e30cc 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -192,7 +192,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver); void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver); -void iq_room_info_request(gchar *room); +void iq_room_info_request(const char * const room); void iq_room_affiliation_list(const char * const room, char *affiliation); void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason); diff --git a/tests/xmpp/stub_xmpp.c b/tests/xmpp/stub_xmpp.c index 53a01c95..21c9862d 100644 --- a/tests/xmpp/stub_xmpp.c +++ b/tests/xmpp/stub_xmpp.c @@ -151,7 +151,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver) {} void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver) {} -void iq_room_info_request(gchar *room) {} +void iq_room_info_request(const char * const room) {} void iq_room_affiliation_list(const char * const room, char *affiliation) {} void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason) {} From 714faeb2e6330a65de6eddbff48a12a6e6f00abc Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 29 Mar 2015 00:55:33 +0000 Subject: [PATCH 3/3] Add callback data to room disco info response handler --- src/command/commands.c | 2 +- src/server_events.c | 9 +-- src/server_events.h | 2 +- src/xmpp/iq.c | 121 ++++++++++++++++++++++++++++++++--------- src/xmpp/xmpp.h | 2 +- tests/xmpp/stub_xmpp.c | 2 +- 6 files changed, 103 insertions(+), 35 deletions(-) diff --git a/src/command/commands.c b/src/command/commands.c index 86285a46..76da2a93 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -1867,7 +1867,7 @@ cmd_info(gchar **args, struct cmd_help_t help) } } else { ProfMucWin *mucwin = wins_get_current_muc(); - iq_room_info_request(mucwin->roomjid); + iq_room_info_request(mucwin->roomjid, TRUE); ui_show_room_info(mucwin); return TRUE; } diff --git a/src/server_events.c b/src/server_events.c index 882c308c..bab6cb13 100644 --- a/src/server_events.c +++ b/src/server_events.c @@ -162,10 +162,12 @@ handle_disco_info(const char *from, GSList *identities, GSList *features) } void -handle_room_disco_info(const char * const room, GSList *identities, GSList *features) +handle_room_disco_info(const char * const room, GSList *identities, GSList *features, gboolean display) { muc_set_features(room, features); - ui_show_room_disco_info(room, identities, features); + if (display) { + ui_show_room_disco_info(room, identities, features); + } } void @@ -699,8 +701,7 @@ handle_muc_self_online(const char * const room, const char * const nick, gboolea ui_room_join(room, TRUE); } - // TODO send disco info request to room - iq_room_info_request(room); + iq_room_info_request(room, FALSE); muc_invites_remove(room); muc_roster_set_complete(room); diff --git a/src/server_events.h b/src/server_events.h index 403c5bb5..b03e11be 100644 --- a/src/server_events.h +++ b/src/server_events.h @@ -58,7 +58,7 @@ void handle_room_message(const char * const room_jid, const char * const nick, const char * const message); void handle_room_join_error(const char * const room, const char * const err); void handle_room_info_error(const char * const room, const char * const error); -void handle_room_disco_info(const char * const room, GSList *identities, GSList *features); +void handle_room_disco_info(const char * const room, GSList *identities, GSList *features, gboolean display); void handle_room_affiliation_list_result_error(const char * const room, const char * const affiliation, const char * const error); void handle_room_affiliation_list(const char * const room, const char * const affiliation, GSList *jids); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 573a50ef..2cbed0dd 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -58,11 +58,17 @@ #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_IQ, type, ctx) +typedef struct p_room_info_data_t { + char *room; + gboolean display; +} ProfRoomInfoData; + static int _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _version_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_info_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); @@ -178,14 +184,18 @@ iq_disco_info_request(gchar *jid) } void -iq_room_info_request(const char * const room) +iq_room_info_request(const char * const room, gboolean display_result) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("room_disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, room, NULL); - xmpp_id_handler_add(conn, _disco_info_response_handler, id, strdup(room)); + ProfRoomInfoData *cb_data = malloc(sizeof(ProfRoomInfoData)); + cb_data->room = strdup(room); + cb_data->display = display_result; + + xmpp_id_handler_add(conn, _room_info_response_handler, id, cb_data); free(id); @@ -1337,6 +1347,82 @@ _item_destroy(DiscoItem *item) } } +static int +_room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + const char *type = xmpp_stanza_get_type(stanza); + ProfRoomInfoData *cb_data = (ProfRoomInfoData *)userdata; + log_info("Received diso#info response for room: %s", cb_data->room); + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + if (cb_data->display) { + char *error_message = stanza_get_error_message(stanza); + handle_room_info_error(cb_data->room, error_message); + free(error_message); + } + free(cb_data->room); + free(cb_data); + return 0; + } + + xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + + if (query != NULL) { + xmpp_stanza_t *child = xmpp_stanza_get_children(query); + GSList *identities = NULL; + GSList *features = NULL; + while (child != NULL) { + const char *stanza_name = xmpp_stanza_get_name(child); + if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { + const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); + if (var != NULL) { + features = g_slist_append(features, strdup(var)); + } + } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { + const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); + const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE); + const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); + + if ((name != NULL) || (category != NULL) || (type != NULL)) { + DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); + + if (name != NULL) { + identity->name = strdup(name); + } else { + identity->name = NULL; + } + if (category != NULL) { + identity->category = strdup(category); + } else { + identity->category = NULL; + } + if (type != NULL) { + identity->type = strdup(type); + } else { + identity->type = NULL; + } + + identities = g_slist_append(identities, identity); + } + } + + child = xmpp_stanza_get_next(child); + } + + handle_room_disco_info(cb_data->room, identities, features, cb_data->display); + + g_slist_free_full(features, free); + g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); + } + + free(cb_data->room); + free(cb_data); + + return 0; +} + static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) @@ -1344,28 +1430,16 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); const char *type = xmpp_stanza_get_type(stanza); - char *room = NULL; - if (userdata) { - room = (char *) userdata; - log_info("Received diso#info response for room: %s", room); + if (from) { + log_info("Received diso#info response from: %s", from); } else { - room = NULL; - if (from) { - log_info("Received diso#info response from: %s", from); - } else { - log_info("Received diso#info response"); - } + log_info("Received diso#info response"); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - if (room) { - handle_room_info_error(room, error_message); - free(room); - } else { - handle_disco_info_error(from, error_message); - } + handle_disco_info_error(from, error_message); free(error_message); return 0; } @@ -1414,20 +1488,13 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta child = xmpp_stanza_get_next(child); } - if (room) { - handle_room_disco_info(room, identities, features); - } else { - handle_disco_info(from, identities, features); - } + handle_disco_info(from, identities, features); g_slist_free_full(features, free); g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); } - if (room) { - free(room); - } - return 1; + return 0; } static int diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index af9e30cc..1dc0c131 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -192,7 +192,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver); void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver); -void iq_room_info_request(const char * const room); +void iq_room_info_request(const char * const room, gboolean display_result); void iq_room_affiliation_list(const char * const room, char *affiliation); void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason); diff --git a/tests/xmpp/stub_xmpp.c b/tests/xmpp/stub_xmpp.c index 21c9862d..1e57f7a8 100644 --- a/tests/xmpp/stub_xmpp.c +++ b/tests/xmpp/stub_xmpp.c @@ -151,7 +151,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver) {} void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver) {} -void iq_room_info_request(const char * const room) {} +void iq_room_info_request(const char * const room, gboolean display) {} void iq_room_affiliation_list(const char * const room, char *affiliation) {} void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason) {}