From 346a5fd71de99a5b9a07308acdad062a235434fa Mon Sep 17 00:00:00 2001 From: Tony Olagbaiye Date: Wed, 2 May 2018 16:55:41 +0100 Subject: [PATCH] pagination --- request/slack-request-channels-list.c | 60 +++++++++++++----- request/slack-request-users-list.c | 88 ++++++++++++++++++++------- slack-channel.c | 31 ++++++++-- slack-channel.h | 5 +- slack-request.c | 1 + slack-request.h | 5 +- slack-user.c | 43 +++++++++++-- slack-user.h | 5 +- slack-workspace.c | 60 +++++++++++++----- slack-workspace.h | 2 + 10 files changed, 234 insertions(+), 66 deletions(-) diff --git a/request/slack-request-channels-list.c b/request/slack-request-channels-list.c index d5c948c..d829a97 100644 --- a/request/slack-request-channels-list.c +++ b/request/slack-request-channels-list.c @@ -12,7 +12,7 @@ static const char *const endpoint = "/api/channels.list?" "token=%s&cursor=%s&" - "exclude_archived=false&exclude_members=true&limit=0"; + "exclude_archived=false&exclude_members=true&limit=20"; static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) { @@ -42,8 +42,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: weechat_printf( request->workspace->buffer, - _("%s%s: error connecting to slack: %s"), - weechat_prefix("error"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) error connecting to slack: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx, in ? (char *)in : "(null)"); request->client_wsi = NULL; break; @@ -52,8 +52,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, status = lws_http_client_http_response(wsi); weechat_printf( request->workspace->buffer, - _("%s%s: retrieving channels... (%d)"), - weechat_prefix("network"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) retrieving channels... (%d)"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx, status); break; @@ -98,8 +98,9 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, { int chunk_count, i; char *json_string; - json_object *response, *ok, *error, *channels; - json_object *channel, *id, *name, *topic; + char cursor[64]; + json_object *response, *ok, *error, *channels, *metadata; + json_object *channel, *id, *name, *topic, *next_cursor; struct t_json_chunk *chunk_ptr; chunk_count = 0; @@ -129,8 +130,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, weechat_printf( request->workspace->buffer, - _("%s%s: got response: %s"), - weechat_prefix("network"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) got response: %s"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx, json_string); response = json_tokener_parse(json_string); @@ -194,6 +195,35 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, json_object_get_string(id), json_object_get_string(name)); } + + metadata = json_object_object_get(response, "response_metadata"); + if (!json_valid(metadata, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + next_cursor = json_object_object_get(metadata, "next_cursor"); + if (!json_valid(next_cursor, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + lws_urlencode(cursor, json_object_get_string(next_cursor), sizeof(cursor)); + + if (cursor[0]) + { + struct t_slack_request *next_request; + + next_request = slack_request_channels_list(request->workspace, + weechat_config_string( + request->workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]), + cursor); + if (next_request) + slack_workspace_register_request(request->workspace, next_request); + } } else { @@ -207,8 +237,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, weechat_printf( request->workspace->buffer, - _("%s%s: failed to retrieve channels: %s"), - weechat_prefix("error"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) failed to retrieve channels: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx, json_object_get_string(error)); } @@ -261,16 +291,16 @@ struct t_slack_request *slack_request_channels_list( { weechat_printf( workspace->buffer, - _("%s%s: error connecting to slack: lws init failed"), - weechat_prefix("error"), SLACK_PLUGIN_NAME); + _("%s%s: (%d) error connecting to slack: lws init failed"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx); return NULL; } else { weechat_printf( workspace->buffer, - _("%s%s: contacting slack.com:443"), - weechat_prefix("network"), SLACK_PLUGIN_NAME); + _("%s%s: (%d) contacting slack.com:443"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx); } memset(&ccinfo, 0, sizeof(ccinfo)); /* otherwise uninitialized garbage */ diff --git a/request/slack-request-users-list.c b/request/slack-request-users-list.c index 3b85506..f8bc4a6 100644 --- a/request/slack-request-users-list.c +++ b/request/slack-request-users-list.c @@ -7,11 +7,12 @@ #include "../slack.h" #include "../slack-workspace.h" #include "../slack-request.h" +#include "../slack-user.h" #include "../request/slack-request-users-list.h" static const char *const endpoint = "/api/users.list?" "token=%s&cursor=%s&" - "exclude_archived=false&exclude_members=true&limit=0"; + "exclude_archived=false&exclude_members=true&limit=20"; static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) { @@ -41,8 +42,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: weechat_printf( request->workspace->buffer, - _("%s%s: error connecting to slack: %s"), - weechat_prefix("error"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) error connecting to slack: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx, in ? (char *)in : "(null)"); request->client_wsi = NULL; break; @@ -51,8 +52,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, status = lws_http_client_http_response(wsi); weechat_printf( request->workspace->buffer, - _("%s%s: retrieving users... (%d)"), - weechat_prefix("network"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) retrieving users... (%d)"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx, status); break; @@ -97,8 +98,9 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, { int chunk_count, i; char *json_string; - json_object *response, *ok, *error, *members; - json_object *user, *id, *name; + char cursor[64]; + json_object *response, *ok, *error, *members, *metadata; + json_object *user, *id, *name, *profile, *display_name, *next_cursor; struct t_json_chunk *chunk_ptr; chunk_count = 0; @@ -128,8 +130,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, weechat_printf( request->workspace->buffer, - _("%s%s: got response: %s"), - weechat_prefix("network"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) got response: %s"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx, json_string); response = json_tokener_parse(json_string); @@ -153,6 +155,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, for (i = json_object_array_length(members); i > 0; i--) { + struct t_slack_user *new_user; + user = json_object_array_get_idx(members, i - 1); if (!json_valid(user, request->workspace)) { @@ -177,12 +181,54 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, return 0; } - weechat_printf( - request->workspace->buffer, - _("%s%s: got user: %s (%s)"), - weechat_prefix("network"), SLACK_PLUGIN_NAME, - json_object_get_string(name), - json_object_get_string(id)); + profile = json_object_object_get(user, "profile"); + if (!json_valid(profile, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + display_name = json_object_object_get(profile, "display_name"); + if (!json_valid(display_name, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + new_user = slack_user_new(request->workspace, + json_object_get_string(id), + json_object_get_string(display_name)); + } + + metadata = json_object_object_get(response, "response_metadata"); + if (!json_valid(metadata, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + next_cursor = json_object_object_get(metadata, "next_cursor"); + if (!json_valid(next_cursor, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + lws_urlencode(cursor, json_object_get_string(next_cursor), sizeof(cursor)); + + if (cursor[0]) + { + struct t_slack_request *next_request; + + next_request = slack_request_users_list(request->workspace, + weechat_config_string( + request->workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]), + cursor); + if (next_request) + slack_workspace_register_request(request->workspace, next_request); } } else @@ -197,8 +243,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, weechat_printf( request->workspace->buffer, - _("%s%s: failed to retrieve users: %s"), - weechat_prefix("error"), SLACK_PLUGIN_NAME, + _("%s%s: (%d) failed to retrieve users: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx, json_object_get_string(error)); } @@ -251,16 +297,16 @@ struct t_slack_request *slack_request_users_list( { weechat_printf( workspace->buffer, - _("%s%s: error connecting to slack: lws init failed"), - weechat_prefix("error"), SLACK_PLUGIN_NAME); + _("%s%s: (%d) error connecting to slack: lws init failed"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx); return NULL; } else { weechat_printf( workspace->buffer, - _("%s%s: contacting slack.com:443"), - weechat_prefix("network"), SLACK_PLUGIN_NAME); + _("%s%s: (%d) contacting slack.com:443"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx); } memset(&ccinfo, 0, sizeof(ccinfo)); /* otherwise uninitialized garbage */ diff --git a/slack-channel.c b/slack-channel.c index 4b855d6..7fdad3e 100644 --- a/slack-channel.c +++ b/slack-channel.c @@ -152,6 +152,29 @@ struct t_gui_buffer *slack_channel_create_buffer(struct t_slack_workspace *works return ptr_buffer; } +void slack_channel_add_nicklist_groups(struct t_slack_workspace *workspace, + struct t_slack_channel *channel) +{ + struct t_gui_buffer *ptr_buffer; + char str_group[32]; + + if (channel && channel->type == SLACK_CHANNEL_TYPE_MPIM) + return; + if (channel && channel->type == SLACK_CHANNEL_TYPE_IM) + return; + + ptr_buffer = channel ? channel->buffer : workspace->buffer; + + snprintf(str_group, sizeof(str_group), "%03d|%s", + 000, "+"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", + 999, "..."); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); +} + struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, enum t_slack_channel_type type, const char *id, const char *name) @@ -159,7 +182,7 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, struct t_slack_channel *new_channel, *ptr_channel; struct t_gui_buffer *ptr_buffer; - if (!workspace || !id) + if (!workspace || !id || !name || !name[0]) return NULL; ptr_channel = slack_channel_search(workspace, id); @@ -206,12 +229,12 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, new_channel->buffer = ptr_buffer; new_channel->buffer_as_string = NULL; - new_channel->prev_channel = NULL; - new_channel->next_channel = NULL; - new_channel->prev_channel = workspace->last_channel; + new_channel->next_channel = NULL; if (workspace->last_channel) (workspace->last_channel)->next_channel = new_channel; + else + workspace->channels = new_channel; workspace->last_channel = new_channel; return new_channel; diff --git a/slack-channel.h b/slack-channel.h index b9b46b5..56c11a6 100644 --- a/slack-channel.h +++ b/slack-channel.h @@ -71,10 +71,13 @@ struct t_slack_channel struct t_slack_channel *slack_channel_search(struct t_slack_workspace *workspace, const char *id); +void slack_channel_add_nicklist_groups(struct t_slack_workspace *workspace, + struct t_slack_channel *channel); + struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, enum t_slack_channel_type type, const char *id, const char *name); -void slack_user_free_all(struct t_slack_workspace *workspace); +void slack_channel_free_all(struct t_slack_workspace *workspace); #endif /*SLACK_CHANNEL_H*/ diff --git a/slack-request.c b/slack-request.c index 6db1816..55343aa 100644 --- a/slack-request.c +++ b/slack-request.c @@ -17,6 +17,7 @@ struct t_slack_request *slack_request_alloc( memset(request, 0, sizeof(struct t_slack_request)); request->workspace = workspace; + request->idx = workspace->idx++; return request; } diff --git a/slack-request.h b/slack-request.h index 21abf8b..9416a71 100644 --- a/slack-request.h +++ b/slack-request.h @@ -5,12 +5,15 @@ struct t_slack_request { struct t_slack_workspace *workspace; + int idx; + char *uri; struct lws *client_wsi; struct lws_context *context; struct t_json_chunk *json_chunks; - struct t_slack_request *next; + struct t_slack_request *prev_request; + struct t_slack_request *next_request; }; struct t_slack_request *slack_request_alloc( diff --git a/slack-user.c b/slack-user.c index c093b97..b78184c 100644 --- a/slack-user.c +++ b/slack-user.c @@ -5,6 +5,7 @@ #include "slack.h" #include "slack-workspace.h" #include "slack-user.h" +#include "slack-channel.h" struct t_slack_user *slack_user_search(struct t_slack_workspace *workspace, const char *id) @@ -24,17 +25,43 @@ struct t_slack_user *slack_user_search(struct t_slack_workspace *workspace, return NULL; } +void slack_user_nicklist_add(struct t_slack_workspace *workspace, + struct t_slack_channel *channel, + struct t_slack_user *user) +{ + struct t_gui_nick_group *ptr_group; + struct t_gui_buffer *ptr_buffer; + + ptr_buffer = channel ? channel->buffer : workspace->buffer; + + ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL, + user->is_away ? + "+" : "..."); + weechat_nicklist_add_nick(ptr_buffer, ptr_group, + user->profile.display_name, + weechat_color(user->is_away ? + "weechat.color.nicklist_away" : + "bar_fg"), + user->is_away ? "+" : "", + weechat_color(""), + 1); +} + struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace, - const char *id) + const char *id, const char *display_name) { struct t_slack_user *new_user, *ptr_user; - if (!workspace || !id) + if (!workspace || !id || !display_name || !display_name[0]) return NULL; + if (!workspace->users) + slack_channel_add_nicklist_groups(workspace, NULL); + ptr_user = slack_user_search(workspace, id); if (ptr_user) { + slack_user_nicklist_add(workspace, NULL, ptr_user); return ptr_user; } @@ -42,7 +69,11 @@ struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace, return NULL; new_user->prev_user = workspace->last_user; - (workspace->last_user)->next_user = new_user; + new_user->next_user = NULL; + if (workspace->last_user) + (workspace->last_user)->next_user = new_user; + else + workspace->users = new_user; workspace->last_user = new_user; new_user->id = strdup(id); @@ -61,11 +92,12 @@ struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace, new_user->profile.status_text = NULL; new_user->profile.status_emoji = NULL; new_user->profile.real_name = NULL; - new_user->profile.display_name = NULL; + new_user->profile.display_name = strdup(display_name); new_user->profile.real_name_normalized = NULL; new_user->profile.email = NULL; new_user->profile.team = NULL; new_user->updated = 0; + new_user->is_away = 0; new_user->is_admin = 0; new_user->is_owner = 0; @@ -77,8 +109,7 @@ struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace, new_user->is_app_user = 0; new_user->has_2fa = 0; - new_user->prev_user = NULL; - new_user->next_user = NULL; + slack_user_nicklist_add(workspace, NULL, new_user); return new_user; } diff --git a/slack-user.h b/slack-user.h index 7bdf5a8..ecf6944 100644 --- a/slack-user.h +++ b/slack-user.h @@ -29,6 +29,7 @@ struct t_slack_user struct t_slack_user_profile profile; int updated; + int is_away; int is_admin; int is_owner; @@ -48,8 +49,8 @@ struct t_slack_user *slack_user_search(struct t_slack_workspace *workspace, const char *id); struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace, - const char *id); + const char *id, const char *display_name); -void slack_channel_free_all(struct t_slack_workspace *workspace); +void slack_user_free_all(struct t_slack_workspace *workspace); #endif /*SLACK_USER_H*/ diff --git a/slack-workspace.c b/slack-workspace.c index fee7b14..ee0c3ca 100644 --- a/slack-workspace.c +++ b/slack-workspace.c @@ -364,12 +364,14 @@ struct t_slack_workspace *slack_workspace_alloc(const char *domain) new_workspace->is_connected = 0; new_workspace->disconnected = 0; + new_workspace->idx = 0; new_workspace->uri = NULL; new_workspace->ws_url = NULL; new_workspace->client_wsi = NULL; new_workspace->context = NULL; new_workspace->json_chunks = NULL; new_workspace->requests = NULL; + new_workspace->last_request = NULL; new_workspace->user = NULL; new_workspace->nick = NULL; @@ -433,8 +435,9 @@ void slack_workspace_free_data(struct t_slack_workspace *workspace) } slack_redirect_free_all(workspace); slack_notify_free_all(workspace); - slack_channel_free_all(workspace); */ + slack_channel_free_all(workspace); + slack_user_free_all(workspace); /* free hashtables */ /* @@ -472,8 +475,19 @@ void slack_workspace_free_data(struct t_slack_workspace *workspace) } while (workspace->requests) { - struct t_slack_request *request_ptr = workspace->requests->next; + struct t_slack_request *request_ptr = workspace->requests->next_request; + workspace->requests->client_wsi = NULL; + if (workspace->requests->context) + { + lws_context_destroy(workspace->requests->context); + workspace->requests->context = NULL; + if (workspace->requests->uri) + { + free(workspace->requests->uri); + workspace->requests->uri = NULL; + } + } free(workspace->requests); workspace->requests = request_ptr; } @@ -548,28 +562,19 @@ void slack_workspace_disconnect(struct t_slack_workspace *workspace, * remove all nicks and write disconnection message on each * channel/private buffer */ - /* + slack_user_free_all(workspace); for (ptr_channel = workspace->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { - slack_nick_free_all(workspace, ptr_channel); - if (ptr_channel->hook_autorejoin) - { - weechat_unhook(ptr_channel->hook_autorejoin); - ptr_channel->hook_autorejoin = NULL; - } - weechat_buffer_set(ptr_channel->buffer, "localvar_del_away", ""); weechat_printf( ptr_channel->buffer, _("%s%s: disconnected from workspace"), weechat_prefix("network"), SLACK_PLUGIN_NAME); } - */ /* remove away status on workspace buffer */ //weechat_buffer_set(workspace->buffer, "localvar_del_away", ""); } - /* slack_workspace_close_connection(workspace); if (workspace->buffer) @@ -580,6 +585,7 @@ void slack_workspace_disconnect(struct t_slack_workspace *workspace, weechat_prefix ("network"), SLACK_PLUGIN_NAME); } + /* workspace->current_retry = 0; if (switch_address) @@ -785,7 +791,7 @@ int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_call continue; for (ptr_request = ptr_workspace->requests; ptr_request; - ptr_request = ptr_request->next) + ptr_request = ptr_request->next_request) { if (ptr_request->client_wsi) { @@ -793,6 +799,8 @@ int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_call } else if (ptr_request->context) { + struct t_slack_request *new_requests; + lws_context_destroy(ptr_request->context); ptr_request->context = NULL; if (ptr_request->uri) @@ -800,6 +808,22 @@ int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_call free(ptr_request->uri); ptr_request->uri = NULL; } + + /* remove request from requests list */ + if (ptr_workspace->last_request == ptr_request) + ptr_workspace->last_request = ptr_request->prev_request; + if (ptr_request->prev_request) + { + (ptr_request->prev_request)->next_request = ptr_request->next_request; + new_requests = ptr_workspace->requests; + } + else + new_requests = ptr_request->next_request; + + if (ptr_request->next_request) + (ptr_request->next_request)->prev_request = ptr_request->prev_request; + + ptr_workspace->requests = new_requests; } } @@ -831,7 +855,11 @@ int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_call void slack_workspace_register_request(struct t_slack_workspace *workspace, struct t_slack_request *request) { - struct t_slack_request *new_tail = workspace->requests; - workspace->requests = request; - workspace->requests->next = new_tail; + request->prev_request = workspace->last_request; + request->next_request = NULL; + if (workspace->last_request) + (workspace->last_request)->next_request = request; + else + workspace->requests = request; + workspace->last_request = request; } diff --git a/slack-workspace.h b/slack-workspace.h index 8ce6f53..dc1f773 100644 --- a/slack-workspace.h +++ b/slack-workspace.h @@ -29,12 +29,14 @@ struct t_slack_workspace int is_connected; int disconnected; + int idx; char *uri; char *ws_url; struct lws *client_wsi; struct lws_context *context; struct t_json_chunk *json_chunks; struct t_slack_request *requests; + struct t_slack_request *last_request; char *user; char *nick;