From 44915eb1b6e6800606bba5c1be30aa7fbb9b1067 Mon Sep 17 00:00:00 2001 From: Tony Olagbaiye Date: Wed, 2 May 2018 23:16:20 +0100 Subject: [PATCH] implement message subtype routing --- Makefile | 2 + api/message/slack-api-message-unimplemented.c | 45 +++++ api/message/slack-api-message-unimplemented.h | 8 + api/slack-api-message.c | 166 ++++++++++++++++++ api/slack-api-message.h | 9 + request/slack-request-channels-list.c | 5 +- request/slack-request-users-list.c | 5 +- slack-api.c | 21 ++- slack-buffer.c | 2 +- slack-channel.c | 6 +- slack-channel.h | 2 + slack-oauth.c | 3 +- slack-teaminfo.c | 3 +- slack-workspace.c | 45 ++++- slack-workspace.h | 2 +- 15 files changed, 309 insertions(+), 15 deletions(-) create mode 100644 api/message/slack-api-message-unimplemented.c create mode 100644 api/message/slack-api-message-unimplemented.h create mode 100644 api/slack-api-message.c create mode 100644 api/slack-api-message.h diff --git a/Makefile b/Makefile index 1098b37..6e0eb15 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,8 @@ SRCS=slack.c \ slack-workspace.c \ api/slack-api-hello.c \ api/slack-api-error.c \ + api/slack-api-message.c \ + api/message/slack-api-message-unimplemented.c \ request/slack-request-channels-list.c \ request/slack-request-users-list.c OBJS=$(subst .c,.o,$(SRCS)) libwebsockets/lib/libwebsockets.a json-c/libjson-c.a diff --git a/api/message/slack-api-message-unimplemented.c b/api/message/slack-api-message-unimplemented.c new file mode 100644 index 0000000..fb66ebd --- /dev/null +++ b/api/message/slack-api-message-unimplemented.c @@ -0,0 +1,45 @@ +#include +#include + +#include "../../weechat-plugin.h" +#include "../../slack.h" +#include "../../slack-workspace.h" +#include "../../slack-api.h" +#include "../../slack-channel.h" +#include "../../slack-user.h" +#include "../slack-api-message.h" + +static const char *subtype = "unimplemented"; + +static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) +{ + if (!object) + { + weechat_printf( + workspace->buffer, + _("%s%s: error handling websocket %smessage.%s%s message: " + "unexpected response from server"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + weechat_color("chat_value"), subtype, weechat_color("reset")); + return 0; + } + + return 1; +} + +int slack_api_message_unimplemented(struct t_slack_workspace *workspace, + json_object *message) +{ + json_object *subtype = json_object_object_get(message, "subtype"); + if (!json_valid(subtype, workspace)) + return 0; + + weechat_printf( + workspace->buffer, + _("%s%s: got unhandled message of type: message.%s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + json_object_get_string(subtype)); + + return 1; +} + diff --git a/api/message/slack-api-message-unimplemented.h b/api/message/slack-api-message-unimplemented.h new file mode 100644 index 0000000..b83b4d8 --- /dev/null +++ b/api/message/slack-api-message-unimplemented.h @@ -0,0 +1,8 @@ +#ifndef _SLACK_API_MESSAGE_UNIMPLEMENTED_H_ +#define _SLACK_API_MESSAGE_UNIMPLEMENTED_H_ + +int slack_api_message_unimplemented( + struct t_slack_workspace *workspace, + json_object *message); + +#endif /*SLACK_API_MESSAGE_UNIMPLEMENTED_H*/ diff --git a/api/slack-api-message.c b/api/slack-api-message.c new file mode 100644 index 0000000..fb385ca --- /dev/null +++ b/api/slack-api-message.c @@ -0,0 +1,166 @@ +#include +#include + +#include "../weechat-plugin.h" +#include "../slack.h" +#include "../slack-workspace.h" +#include "../slack-api.h" +#include "../slack-channel.h" +#include "../slack-user.h" +#include "slack-api-message.h" +#include "message/slack-api-message-unimplemented.h" + +static const char *type = "message"; + +struct stringcase +{ + const char *string; + int (*func)(struct t_slack_workspace *workspace, + json_object *message); +}; + +static struct stringcase cases[] = +{ { "bot_message", &slack_api_message_unimplemented } +, { "channel_archive", &slack_api_message_unimplemented } +, { "channel_join", &slack_api_message_unimplemented } +, { "channel_leave", &slack_api_message_unimplemented } +, { "channel_name", &slack_api_message_unimplemented } +, { "channel_purpose", &slack_api_message_unimplemented } +, { "channel_topic", &slack_api_message_unimplemented } +, { "channel_unarchive", &slack_api_message_unimplemented } +, { "file_comment", &slack_api_message_unimplemented } +, { "file_mention", &slack_api_message_unimplemented } +, { "file_share", &slack_api_message_unimplemented } +, { "group_archive", &slack_api_message_unimplemented } +, { "group_join", &slack_api_message_unimplemented } +, { "group_leave", &slack_api_message_unimplemented } +, { "group_name", &slack_api_message_unimplemented } +, { "group_purpose", &slack_api_message_unimplemented } +, { "group_topic", &slack_api_message_unimplemented } +, { "group_unarchive", &slack_api_message_unimplemented } +, { "me_message", &slack_api_message_unimplemented } +, { "message_changed", &slack_api_message_unimplemented } +, { "message_deleted", &slack_api_message_unimplemented } +, { "message_replied", &slack_api_message_unimplemented } +, { "pinned_item", &slack_api_message_unimplemented } +, { "reply_broadcast", &slack_api_message_unimplemented } +, { "thread_broadcast", &slack_api_message_unimplemented } +, { "unpinned_item", &slack_api_message_unimplemented } +}; + +static int stringcase_cmp(const void *p1, const void *p2) +{ + return strcasecmp(((struct stringcase*)p1)->string, ((struct stringcase*)p2)->string); +} + +void slack_api_message_init() +{ + size_t case_count = sizeof(cases) / sizeof(cases[0]); + qsort(cases, case_count, sizeof(struct stringcase), stringcase_cmp); +} + +static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) +{ + if (!object) + { + weechat_printf( + workspace->buffer, + _("%s%s: error handling websocket %s%s%s message: " + "unexpected response from server"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + weechat_color("chat_value"), type, weechat_color("reset")); + return 0; + } + + return 1; +} + +int slack_api_message_message_handle(struct t_slack_workspace *workspace, + const char *channel, const char *user, + const char *text, const char *ts) +{ + struct t_slack_channel *ptr_channel; + struct t_slack_user *ptr_user; + + (void) ts; + + ptr_channel = slack_channel_search(workspace, channel); + if (!ptr_channel) + return 1; /* silently ignore if channel hasn't been loaded yet */ + ptr_user = slack_user_search(workspace, user); + if (!ptr_user) + return 1; /* silently ignore if user hasn't been loaded yet */ + + weechat_printf( + workspace->buffer, + _("%s%s: message [%s]: <%s> %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + ptr_channel->name, ptr_user->profile.display_name, text); + + return 1; +} + +int slack_api_message_route_message(struct t_slack_workspace *workspace, + const char *subtype, + json_object *message) +{ + struct stringcase key; + key.string = type; + + size_t case_count = sizeof(cases) / sizeof(cases[0]); + void *entry_ptr = bsearch(&key, cases, case_count, + sizeof(struct stringcase), stringcase_cmp); + + if (entry_ptr) + { + struct stringcase *entry = (struct stringcase *)entry_ptr; + return (*entry->func)(workspace, message); + } + else + { + weechat_printf( + workspace->buffer, + _("%s%s: got unhandled message of type: message.%s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + subtype); + return 1; + } +} + +int slack_api_message(struct t_slack_workspace *workspace, + json_object *message) +{ + json_object *subtype, *channel, *user, *text, *ts; + + subtype = json_object_object_get(message, "subtype"); + if (!subtype) + { /* normal message */ + channel = json_object_object_get(message, "channel"); + if (!json_valid(channel, workspace)) + return 0; + + user = json_object_object_get(message, "user"); + if (!json_valid(user, workspace)) + return 0; + + text = json_object_object_get(message, "text"); + if (!json_valid(text, workspace)) + return 0; + + ts = json_object_object_get(message, "ts"); + if (!json_valid(ts, workspace)) + return 0; + + return slack_api_message_message_handle(workspace, + json_object_get_string(channel), + json_object_get_string(user), + json_object_get_string(text), + json_object_get_string(ts)); + } + else + { /* special message */ + return slack_api_message_route_message(workspace, + json_object_get_string(subtype), + message); + } +} diff --git a/api/slack-api-message.h b/api/slack-api-message.h new file mode 100644 index 0000000..eed80e3 --- /dev/null +++ b/api/slack-api-message.h @@ -0,0 +1,9 @@ +#ifndef _SLACK_API_MESSAGE_H_ +#define _SLACK_API_MESSAGE_H_ + +int slack_api_message(struct t_slack_workspace *workspace, + json_object *message); + +void slack_api_message_init(); + +#endif /*SLACK_API_MESSAGE_H*/ diff --git a/request/slack-request-channels-list.c b/request/slack-request-channels-list.c index d829a97..6227875 100644 --- a/request/slack-request-channels-list.c +++ b/request/slack-request-channels-list.c @@ -22,7 +22,7 @@ static inline int json_valid(json_object *object, struct t_slack_workspace *work workspace->buffer, _("%s%s: error retrieving channels: unexpected response from server"), weechat_prefix("error"), SLACK_PLUGIN_NAME); - __asm__("int3"); + //__asm__("int3"); return 0; } @@ -247,7 +247,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: request->client_wsi = NULL; - lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + /* Does not doing this cause a leak? + lws_cancel_service(lws_get_context(wsi));*/ /* abort poll wait */ break; default: diff --git a/request/slack-request-users-list.c b/request/slack-request-users-list.c index f8bc4a6..d0e051a 100644 --- a/request/slack-request-users-list.c +++ b/request/slack-request-users-list.c @@ -22,7 +22,7 @@ static inline int json_valid(json_object *object, struct t_slack_workspace *work workspace->buffer, _("%s%s: error retrieving users: unexpected response from server"), weechat_prefix("error"), SLACK_PLUGIN_NAME); - __asm__("int3"); + //__asm__("int3"); return 0; } @@ -253,7 +253,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: request->client_wsi = NULL; - lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + /* Does not doing this cause a leak? + lws_cancel_service(lws_get_context(wsi));*/ /* abort poll wait */ break; default: diff --git a/slack-api.c b/slack-api.c index ff92721..4492d18 100644 --- a/slack-api.c +++ b/slack-api.c @@ -9,6 +9,7 @@ #include "slack-api.h" #include "api/slack-api-hello.h" #include "api/slack-api-error.h" +#include "api/slack-api-message.h" struct stringcase { @@ -18,8 +19,9 @@ struct stringcase }; struct stringcase cases[] = -{ { "hello", slack_api_hello } -, { "error", slack_api_error } +{ { "hello", &slack_api_hello } +, { "error", &slack_api_error } +, { "message", &slack_api_message } }; static int stringcase_cmp(const void *p1, const void *p2) @@ -80,6 +82,9 @@ static int callback_ws(struct lws* wsi, enum lws_callback_reasons reason, workspace->buffer, _("%s%s: unexpected data received from websocket: closing"), weechat_prefix("error"), SLACK_PLUGIN_NAME); + + slack_workspace_disconnect(workspace, 0); + json_object_put(response); free(json_string); return -1; @@ -88,6 +93,18 @@ static int callback_ws(struct lws* wsi, enum lws_callback_reasons reason, if (!slack_api_route_message(workspace, json_object_get_string(type), response)) { + weechat_printf( + workspace->buffer, + _("%s%s: error while handling message: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + json_string); + weechat_printf( + workspace->buffer, + _("%s%s: closing connection."), + weechat_prefix("error"), SLACK_PLUGIN_NAME); + + slack_workspace_disconnect(workspace, 0); + json_object_put(response); free(json_string); return -1; diff --git a/slack-buffer.c b/slack-buffer.c index 40d49c0..04ff85e 100644 --- a/slack-buffer.c +++ b/slack-buffer.c @@ -87,7 +87,7 @@ int slack_buffer_close_cb(const void *pointer, void *data, if (!ptr_workspace->disconnected) { //slack_command_quit_workspace(ptr_workspace, NULL); - slack_workspace_disconnect(ptr_workspace, 0, 0); + slack_workspace_disconnect(ptr_workspace, 0); } ptr_workspace->buffer = NULL; diff --git a/slack-channel.c b/slack-channel.c index 7fdad3e..d6255e2 100644 --- a/slack-channel.c +++ b/slack-channel.c @@ -181,6 +181,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; + char buffer_name[SLACK_CHANNEL_NAME_MAX_LEN + 2]; if (!workspace || !id || !name || !name[0]) return NULL; @@ -191,7 +192,10 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, return ptr_channel; } - ptr_buffer = slack_channel_create_buffer(workspace, type, name); + buffer_name[0] = '#'; + strncpy(&buffer_name[1], name, SLACK_CHANNEL_NAME_MAX_LEN + 1); + + ptr_buffer = slack_channel_create_buffer(workspace, type, buffer_name); if (!ptr_buffer) return NULL; diff --git a/slack-channel.h b/slack-channel.h index 56c11a6..f5892be 100644 --- a/slack-channel.h +++ b/slack-channel.h @@ -1,6 +1,8 @@ #ifndef _SLACK_CHANNEL_H_ #define _SLACK_CHANNEL_H_ +#define SLACK_CHANNEL_NAME_MAX_LEN 22 + enum t_slack_channel_type { SLACK_CHANNEL_TYPE_CHANNEL, diff --git a/slack-oauth.c b/slack-oauth.c index ca46285..5bd2845 100644 --- a/slack-oauth.c +++ b/slack-oauth.c @@ -135,7 +135,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP: client_wsi = NULL; - lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + /* Does not doing this cause a leak? + lws_cancel_service(lws_get_context(wsi));*/ /* abort poll wait */ break; default: diff --git a/slack-teaminfo.c b/slack-teaminfo.c index 431bfd7..ba1347e 100644 --- a/slack-teaminfo.c +++ b/slack-teaminfo.c @@ -230,7 +230,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: client_wsi = NULL; - lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + /* Does not doing this cause a leak? + lws_cancel_service(lws_get_context(wsi));*/ /* abort poll wait */ break; default: diff --git a/slack-workspace.c b/slack-workspace.c index ee0c3ca..8438fba 100644 --- a/slack-workspace.c +++ b/slack-workspace.c @@ -249,7 +249,8 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: workspace->client_wsi = NULL; - lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + /* Does not doing this cause a leak? + lws_cancel_service(lws_get_context(wsi));*/ /* abort poll wait */ break; default: @@ -548,9 +549,8 @@ void slack_workspace_free_all() } void slack_workspace_disconnect(struct t_slack_workspace *workspace, - int switch_address, int reconnect) + int reconnect) { - (void) switch_address; (void) reconnect; struct t_slack_channel *ptr_channel; @@ -563,9 +563,11 @@ void slack_workspace_disconnect(struct t_slack_workspace *workspace, * channel/private buffer */ slack_user_free_all(workspace); + weechat_nicklist_remove_all(workspace->buffer); for (ptr_channel = workspace->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { + weechat_nicklist_remove_all(ptr_channel->buffer); weechat_printf( ptr_channel->buffer, _("%s%s: disconnected from workspace"), @@ -650,7 +652,7 @@ void slack_workspace_disconnect_all() for (ptr_workspace = slack_workspaces; ptr_workspace; ptr_workspace = ptr_workspace->next_workspace) { - slack_workspace_disconnect(ptr_workspace, 0, 0); + slack_workspace_disconnect(ptr_workspace, 0); } } @@ -690,9 +692,44 @@ struct t_gui_buffer *slack_workspace_create_buffer(struct t_slack_workspace *wor void slack_workspace_close_connection(struct t_slack_workspace *workspace) { + struct t_slack_request *ptr_request; + workspace->is_connected = 0; workspace->client_wsi = NULL; workspace->context = NULL; + + for (ptr_request = workspace->requests; ptr_request; + ptr_request = ptr_request->next_request) + { + if (ptr_request->context) + { + struct t_slack_request *new_requests; + + lws_context_destroy(ptr_request->context); + ptr_request->context = NULL; + if (ptr_request->uri) + { + free(ptr_request->uri); + ptr_request->uri = NULL; + } + + /* remove request from requests list */ + if (workspace->last_request == ptr_request) + workspace->last_request = ptr_request->prev_request; + if (ptr_request->prev_request) + { + (ptr_request->prev_request)->next_request = ptr_request->next_request; + new_requests = workspace->requests; + } + else + new_requests = ptr_request->next_request; + + if (ptr_request->next_request) + (ptr_request->next_request)->prev_request = ptr_request->prev_request; + + workspace->requests = new_requests; + } + } } void slack_workspace_websocket_create(struct t_slack_workspace *workspace) diff --git a/slack-workspace.h b/slack-workspace.h index dc1f773..9861ab9 100644 --- a/slack-workspace.h +++ b/slack-workspace.h @@ -61,7 +61,7 @@ void slack_workspace_free_data(struct t_slack_workspace *workspace); void slack_workspace_free(struct t_slack_workspace *workspace); void slack_workspace_free_all(); void slack_workspace_disconnect(struct t_slack_workspace *workspace, - int switch_address, int reconnect); + int reconnect); void slack_workspace_disconnect_all(); void slack_workspace_close_connection(struct t_slack_workspace *workspace); int slack_workspace_connect(struct t_slack_workspace *workspace);