diff --git a/src/common.c b/src/common.c index 94b2872c..2d1ac3d7 100644 --- a/src/common.c +++ b/src/common.c @@ -37,6 +37,9 @@ // and page size is at least 4KB #define READ_BUF_SIZE 4088 +// for generating ids +static int unique_id = 0; + struct curl_data_t { char *buffer; @@ -394,6 +397,19 @@ xdg_get_data_home(void) } } +char * +get_unique_id(void) +{ + char *result = NULL; + unique_id++; + GString *result_str = g_string_new(""); + g_string_printf(result_str, "prof%d", unique_id); + result = result_str->str; + g_string_free(result_str, FALSE); + + return result; +} + static size_t _data_callback(void *ptr, size_t size, size_t nmemb, void *data) { diff --git a/src/common.h b/src/common.h index 96c5d08c..b87f2a97 100644 --- a/src/common.h +++ b/src/common.h @@ -92,4 +92,6 @@ const char * string_from_resource_presence(resource_presence_t presence); resource_presence_t resource_presence_from_string(const char * const str); contact_presence_t contact_presence_from_resource_presence(resource_presence_t resource_presence); +char * get_unique_id(void); + #endif diff --git a/src/profanity.c b/src/profanity.c index d67cd6a9..9c729ca1 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -164,6 +164,22 @@ prof_handle_not_in_group(const char * const contact, ui_current_page_off(); } +void +prof_handle_group_add(const char * const contact, + const char * const group) +{ + ui_group_added(contact, group); + ui_current_page_off(); +} + +void +prof_handle_group_remove(const char * const contact, + const char * const group) +{ + ui_group_removed(contact, group); + ui_current_page_off(); +} + void prof_handle_error_message(const char *from, const char *err_msg) { diff --git a/src/profanity.h b/src/profanity.h index d7e37870..0cd59fd0 100644 --- a/src/profanity.h +++ b/src/profanity.h @@ -84,5 +84,7 @@ void prof_handle_roster_add(const char * const barejid, const char * const name) void prof_handle_roster_remove(const char * const barejid); void prof_handle_already_in_group(const char * const contact, const char * const group); void prof_handle_not_in_group(const char * const contact, const char * const group); +void prof_handle_group_add(const char * const contact, const char * const group); +void prof_handle_group_remove(const char * const contact, const char * const group); #endif diff --git a/src/ui/core.c b/src/ui/core.c index 8f04a375..126fe127 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -467,6 +467,18 @@ ui_contact_not_in_group(const char * const contact, const char * const group) cons_show("%s is not currently in group %s", contact, group); } +void +ui_group_added(const char * const contact, const char * const group) +{ + cons_show("%s added to group %s", contact, group); +} + +void +ui_group_removed(const char * const contact, const char * const group) +{ + cons_show("%s removed from group %s", contact, group); +} + void ui_contact_online(const char * const barejid, const char * const resource, const char * const show, const char * const status, GDateTime *last_activity) diff --git a/src/ui/ui.h b/src/ui/ui.h index 65880b2a..061f445b 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -116,6 +116,8 @@ void ui_roster_add(const char * const barejid, const char * const name); void ui_roster_remove(const char * const barejid); void ui_contact_already_in_group(const char * const contact, const char * const group); void ui_contact_not_in_group(const char * const contact, const char * const group); +void ui_group_added(const char * const contact, const char * const group); +void ui_group_removed(const char * const contact, const char * const group); // contact status functions void ui_status_room(const char * const contact); diff --git a/src/xmpp/roster.c b/src/xmpp/roster.c index 262ad0b1..f96a3f84 100644 --- a/src/xmpp/roster.c +++ b/src/xmpp/roster.c @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -55,12 +56,26 @@ static GHashTable *contacts; // nickname to jid map static GHashTable *name_to_barejid; +// callback data for group commands +typedef struct _group_data { + char *name; + char *group; +} GroupData; + // event handlers static int _roster_handle_push(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _roster_handle_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +// id handlers +static int +_group_add_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata); +static int +_group_remove_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata); + // helper functions static void _add_name_and_barejid(const char * const name, const char * const barejid); @@ -141,7 +156,7 @@ roster_add_new(const char * const barejid, const char * const name) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_roster_set(ctx, barejid, name, NULL); + xmpp_stanza_t *iq = stanza_create_roster_set(ctx, NULL, barejid, name, NULL); xmpp_send(conn, iq); xmpp_stanza_release(iq); } @@ -279,7 +294,7 @@ roster_change_name(const char * const barejid, const char * const new_name) xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_roster_set(ctx, barejid, new_name, + xmpp_stanza_t *iq = stanza_create_roster_set(ctx, NULL, barejid, new_name, groups); xmpp_send(conn, iq); xmpp_stanza_release(iq); @@ -312,13 +327,40 @@ roster_add_to_group(const char * const group, const char * const barejid) xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_roster_set(ctx, barejid, + + // add an id handler to handle the response + char *unique_id = get_unique_id(); + GroupData *data = malloc(sizeof(GroupData)); + data->group = strdup(group); + if (p_contact_name(contact) != NULL) { + data->name = strdup(p_contact_name(contact)); + } else { + data->name = strdup(p_contact_barejid(contact)); + } + + xmpp_id_handler_add(conn, _group_add_handler, unique_id, data); + xmpp_stanza_t *iq = stanza_create_roster_set(ctx, unique_id, barejid, p_contact_name(contact), new_groups); xmpp_send(conn, iq); xmpp_stanza_release(iq); + free(unique_id); } } +static int +_group_add_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + if (userdata != NULL) { + GroupData *data = userdata; + prof_handle_group_add(data->name, data->group); + free(data->name); + free(data->group); + free(userdata); + } + return 0; +} + void roster_remove_from_group(const char * const group, const char * const barejid) { @@ -345,14 +387,41 @@ roster_remove_from_group(const char * const group, const char * const barejid) xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_roster_set(ctx, barejid, + + // add an id handler to handle the response + char *unique_id = get_unique_id(); + GroupData *data = malloc(sizeof(GroupData)); + data->group = strdup(group); + if (p_contact_name(contact) != NULL) { + data->name = strdup(p_contact_name(contact)); + } else { + data->name = strdup(p_contact_barejid(contact)); + } + + xmpp_id_handler_add(conn, _group_remove_handler, unique_id, data); + xmpp_stanza_t *iq = stanza_create_roster_set(ctx, unique_id, barejid, p_contact_name(contact), new_groups); xmpp_send(conn, iq); xmpp_stanza_release(iq); + free(unique_id); } } +static int +_group_remove_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + if (userdata != NULL) { + GroupData *data = userdata; + prof_handle_group_remove(data->name, data->group); + free(data->name); + free(data->group); + free(userdata); + } + return 0; +} + gboolean roster_has_pending_subscriptions(void) { diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index a5b7788a..d2de44f0 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -119,12 +119,15 @@ stanza_create_roster_remove_set(xmpp_ctx_t *ctx, const char * const barejid) } xmpp_stanza_t * -stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const jid, - const char * const handle, GSList *groups) +stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, + const char * const jid, const char * const handle, GSList *groups) { xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); + if (id != NULL) { + xmpp_stanza_set_id(iq, id); + } xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index d1f55890..ad777f24 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -179,8 +179,8 @@ xmpp_stanza_t * stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char * const char * stanza_get_status(xmpp_stanza_t *stanza, char *def); char * stanza_get_show(xmpp_stanza_t *stanza, char *def); -xmpp_stanza_t * stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const jid, - const char * const handle, GSList *groups); +xmpp_stanza_t * stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, + const char * const jid, const char * const handle, GSList *groups); xmpp_stanza_t * stanza_create_roster_remove_set(xmpp_ctx_t *ctx, const char * const barejid);