diff --git a/Makefile b/Makefile index cb2b6a2..1098b37 100644 --- a/Makefile +++ b/Makefile @@ -8,12 +8,19 @@ LDLIBS=-lgnutls SRCS=slack.c \ slack-api.c \ slack-buffer.c \ + slack-channel.c \ slack-config.c \ slack-command.c \ slack-input.c \ slack-oauth.c \ + slack-request.c \ slack-teaminfo.c \ - slack-workspace.c + slack-user.c \ + slack-workspace.c \ + api/slack-api-hello.c \ + api/slack-api-error.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 all: libwebsockets/lib/libwebsockets.a json-c/libjson-c.a weechat-slack diff --git a/api/slack-api-error.c b/api/slack-api-error.c new file mode 100644 index 0000000..6fe75bc --- /dev/null +++ b/api/slack-api-error.c @@ -0,0 +1,59 @@ +#include + +#include "../weechat-plugin.h" +#include "../slack.h" +#include "../slack-workspace.h" +#include "../slack-api.h" +#include "slack-api-error.h" + +static const char *type = "error"; + +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_error_handle(struct t_slack_workspace *workspace, + int code, const char *msg) +{ + weechat_printf( + workspace->buffer, + _("%s%s: error %d: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + code, msg); + + return 0; +} + +int slack_api_error(struct t_slack_workspace *workspace, + json_object *message) +{ + json_object *error, *code, *msg; + + error = json_object_object_get(message, "error"); + if (!json_valid(error, workspace)) + return 0; + + code = json_object_object_get(error, "code"); + if (!json_valid(code, workspace)) + return 0; + + msg = json_object_object_get(error, "msg"); + if (!json_valid(msg, workspace)) + return 0; + + return slack_api_error_handle(workspace, + json_object_get_int(code), + json_object_get_string(msg)); +} diff --git a/api/slack-api-error.h b/api/slack-api-error.h new file mode 100644 index 0000000..19afd9d --- /dev/null +++ b/api/slack-api-error.h @@ -0,0 +1,7 @@ +#ifndef _SLACK_API_ERROR_H_ +#define _SLACK_API_ERROR_H_ + +int slack_api_error(struct t_slack_workspace *workspace, + json_object *message); + +#endif /*SLACK_API_ERROR_H*/ diff --git a/api/slack-api-hello.c b/api/slack-api-hello.c new file mode 100644 index 0000000..406cbd3 --- /dev/null +++ b/api/slack-api-hello.c @@ -0,0 +1,43 @@ +#include + +#include "../weechat-plugin.h" +#include "../slack.h" +#include "../slack-workspace.h" +#include "../slack-api.h" +#include "slack-api-hello.h" +#include "../request/slack-request-channels-list.h" +#include "../request/slack-request-users-list.h" + +int slack_api_hello_handle(struct t_slack_workspace *workspace) +{ + struct t_slack_request *request; + + weechat_printf( + workspace->buffer, + _("%s%s: connected!"), + weechat_prefix("network"), SLACK_PLUGIN_NAME); + + request = slack_request_users_list(workspace, + weechat_config_string( + workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]), + ""); + if (request) + slack_workspace_register_request(workspace, request); + + request = slack_request_channels_list(workspace, + weechat_config_string( + workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]), + ""); + if (request) + slack_workspace_register_request(workspace, request); + + return 1; +} + +int slack_api_hello(struct t_slack_workspace *workspace, + json_object *message) +{ + (void) message; + + return slack_api_hello_handle(workspace); +} diff --git a/api/slack-api-hello.h b/api/slack-api-hello.h new file mode 100644 index 0000000..08432f3 --- /dev/null +++ b/api/slack-api-hello.h @@ -0,0 +1,7 @@ +#ifndef _SLACK_API_HELLO_H_ +#define _SLACK_API_HELLO_H_ + +int slack_api_hello(struct t_slack_workspace *workspace, + json_object *message); + +#endif /*SLACK_API_HELLO_H*/ diff --git a/request/slack-request-channels-list.c b/request/slack-request-channels-list.c new file mode 100644 index 0000000..d5c948c --- /dev/null +++ b/request/slack-request-channels-list.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include + +#include "../weechat-plugin.h" +#include "../slack.h" +#include "../slack-workspace.h" +#include "../slack-request.h" +#include "../slack-channel.h" +#include "../request/slack-request-channels-list.h" + +static const char *const endpoint = "/api/channels.list?" + "token=%s&cursor=%s&" + "exclude_archived=false&exclude_members=true&limit=0"; + +static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) +{ + if (!object) + { + weechat_printf( + workspace->buffer, + _("%s%s: error retrieving channels: unexpected response from server"), + weechat_prefix("error"), SLACK_PLUGIN_NAME); + __asm__("int3"); + return 0; + } + + return 1; +} + +static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct t_slack_request *request = (struct t_slack_request *)user; + + int status; + + switch (reason) + { + /* because we are protocols[0] ... */ + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + weechat_printf( + request->workspace->buffer, + _("%s%s: error connecting to slack: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + in ? (char *)in : "(null)"); + request->client_wsi = NULL; + break; + + case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: + status = lws_http_client_http_response(wsi); + weechat_printf( + request->workspace->buffer, + _("%s%s: retrieving channels... (%d)"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, + status); + break; + + /* chunks of chunked content, with header removed */ + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: + { + struct t_json_chunk *new_chunk, *last_chunk; + + new_chunk = malloc(sizeof(*new_chunk)); + new_chunk->data = malloc((1024 * sizeof(char)) + 1); + new_chunk->data[0] = '\0'; + new_chunk->next = NULL; + + strncat(new_chunk->data, in, (int)len); + + if (request->json_chunks) + { + for (last_chunk = request->json_chunks; last_chunk->next; + last_chunk = last_chunk->next); + last_chunk->next = new_chunk; + } + else + { + request->json_chunks = new_chunk; + } + } + return 0; /* don't passthru */ + + /* uninterpreted http content */ + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: + { + char buffer[1024 + LWS_PRE]; + char *px = buffer + LWS_PRE; + int lenx = sizeof(buffer) - LWS_PRE; + + if (lws_http_client_read(wsi, &px, &lenx) < 0) + return -1; + } + return 0; /* don't passthru */ + + case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: + { + int chunk_count, i; + char *json_string; + json_object *response, *ok, *error, *channels; + json_object *channel, *id, *name, *topic; + struct t_json_chunk *chunk_ptr; + + chunk_count = 0; + if (request->json_chunks) + { + chunk_count++; + for (chunk_ptr = request->json_chunks; chunk_ptr->next; + chunk_ptr = chunk_ptr->next) + { + chunk_count++; + } + } + + json_string = malloc((1024 * sizeof(char) * chunk_count) + 1); + json_string[0] = '\0'; + + chunk_ptr = request->json_chunks; + for (i = 0; i < chunk_count; i++) + { + strncat(json_string, chunk_ptr->data, 1024); + chunk_ptr = chunk_ptr->next; + + free(request->json_chunks->data); + free(request->json_chunks); + request->json_chunks = chunk_ptr; + } + + weechat_printf( + request->workspace->buffer, + _("%s%s: got response: %s"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, + json_string); + + response = json_tokener_parse(json_string); + ok = json_object_object_get(response, "ok"); + if (!json_valid(ok, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + if(json_object_get_boolean(ok)) + { + channels = json_object_object_get(response, "channels"); + if (!json_valid(channels, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + for (i = json_object_array_length(channels); i > 0; i--) + { + struct t_slack_channel *new_channel; + + channel = json_object_array_get_idx(channels, i - 1); + if (!json_valid(channel, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + id = json_object_object_get(channel, "id"); + if (!json_valid(id, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + name = json_object_object_get(channel, "name"); + if (!json_valid(name, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + topic = json_object_object_get(channel, "topic"); + if (!json_valid(topic, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + new_channel = slack_channel_new( + request->workspace, + SLACK_CHANNEL_TYPE_CHANNEL, + json_object_get_string(id), + json_object_get_string(name)); + } + } + else + { + error = json_object_object_get(response, "error"); + if (!json_valid(error, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + weechat_printf( + request->workspace->buffer, + _("%s%s: failed to retrieve channels: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + json_object_get_string(error)); + } + + json_object_put(response); + free(json_string); + } + case LWS_CALLBACK_CLOSED_CLIENT_HTTP: + request->client_wsi = NULL; + lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + break; + + default: + break; + } + + return lws_callback_http_dummy(wsi, reason, user, in, len); +} + +static const struct lws_protocols protocols[] = { + { + "http", + callback_http, + 0, + 0, + }, + { NULL, NULL, 0, 0 } +}; + +struct t_slack_request *slack_request_channels_list( + struct t_slack_workspace *workspace, + const char *token, const char *cursor) +{ + struct t_slack_request *request; + struct lws_context_creation_info ctxinfo; + struct lws_client_connect_info ccinfo; + + request = slack_request_alloc(workspace); + + size_t urilen = snprintf(NULL, 0, endpoint, token, cursor) + 1; + request->uri = malloc(urilen); + snprintf(request->uri, urilen, endpoint, token, cursor); + + memset(&ctxinfo, 0, sizeof(ctxinfo)); /* otherwise uninitialized garbage */ + ctxinfo.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + ctxinfo.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ + ctxinfo.protocols = protocols; + + request->context = lws_create_context(&ctxinfo); + if (!request->context) + { + weechat_printf( + workspace->buffer, + _("%s%s: error connecting to slack: lws init failed"), + weechat_prefix("error"), SLACK_PLUGIN_NAME); + return NULL; + } + else + { + weechat_printf( + workspace->buffer, + _("%s%s: contacting slack.com:443"), + weechat_prefix("network"), SLACK_PLUGIN_NAME); + } + + memset(&ccinfo, 0, sizeof(ccinfo)); /* otherwise uninitialized garbage */ + ccinfo.context = request->context; + ccinfo.ssl_connection = LCCSCF_USE_SSL; + ccinfo.port = 443; + ccinfo.address = "slack.com"; + ccinfo.path = request->uri; + ccinfo.host = ccinfo.address; + ccinfo.origin = ccinfo.address; + ccinfo.method = "GET"; + ccinfo.protocol = protocols[0].name; + ccinfo.pwsi = &request->client_wsi; + ccinfo.userdata = request; + + lws_client_connect_via_info(&ccinfo); + + return request; +} diff --git a/request/slack-request-channels-list.h b/request/slack-request-channels-list.h new file mode 100644 index 0000000..e41545a --- /dev/null +++ b/request/slack-request-channels-list.h @@ -0,0 +1,8 @@ +#ifndef _SLACK_REQUEST_CHANNELS_LIST_H_ +#define _SLACK_REQUEST_CHANNELS_LIST_H_ + +struct t_slack_request *slack_request_channels_list( + struct t_slack_workspace *workspace, + const char *token, const char *cursor); + +#endif /*SLACK_REQUEST_CHANNELS_LIST_H*/ diff --git a/request/slack-request-users-list.c b/request/slack-request-users-list.c new file mode 100644 index 0000000..3b85506 --- /dev/null +++ b/request/slack-request-users-list.c @@ -0,0 +1,282 @@ +#include +#include +#include +#include + +#include "../weechat-plugin.h" +#include "../slack.h" +#include "../slack-workspace.h" +#include "../slack-request.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"; + +static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) +{ + if (!object) + { + weechat_printf( + workspace->buffer, + _("%s%s: error retrieving users: unexpected response from server"), + weechat_prefix("error"), SLACK_PLUGIN_NAME); + __asm__("int3"); + return 0; + } + + return 1; +} + +static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct t_slack_request *request = (struct t_slack_request *)user; + + int status; + + switch (reason) + { + /* because we are protocols[0] ... */ + case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: + weechat_printf( + request->workspace->buffer, + _("%s%s: error connecting to slack: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + in ? (char *)in : "(null)"); + request->client_wsi = NULL; + break; + + case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: + status = lws_http_client_http_response(wsi); + weechat_printf( + request->workspace->buffer, + _("%s%s: retrieving users... (%d)"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, + status); + break; + + /* chunks of chunked content, with header removed */ + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: + { + struct t_json_chunk *new_chunk, *last_chunk; + + new_chunk = malloc(sizeof(*new_chunk)); + new_chunk->data = malloc((1024 * sizeof(char)) + 1); + new_chunk->data[0] = '\0'; + new_chunk->next = NULL; + + strncat(new_chunk->data, in, (int)len); + + if (request->json_chunks) + { + for (last_chunk = request->json_chunks; last_chunk->next; + last_chunk = last_chunk->next); + last_chunk->next = new_chunk; + } + else + { + request->json_chunks = new_chunk; + } + } + return 0; /* don't passthru */ + + /* uninterpreted http content */ + case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: + { + char buffer[1024 + LWS_PRE]; + char *px = buffer + LWS_PRE; + int lenx = sizeof(buffer) - LWS_PRE; + + if (lws_http_client_read(wsi, &px, &lenx) < 0) + return -1; + } + return 0; /* don't passthru */ + + case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: + { + int chunk_count, i; + char *json_string; + json_object *response, *ok, *error, *members; + json_object *user, *id, *name; + struct t_json_chunk *chunk_ptr; + + chunk_count = 0; + if (request->json_chunks) + { + chunk_count++; + for (chunk_ptr = request->json_chunks; chunk_ptr->next; + chunk_ptr = chunk_ptr->next) + { + chunk_count++; + } + } + + json_string = malloc((1024 * sizeof(char) * chunk_count) + 1); + json_string[0] = '\0'; + + chunk_ptr = request->json_chunks; + for (i = 0; i < chunk_count; i++) + { + strncat(json_string, chunk_ptr->data, 1024); + chunk_ptr = chunk_ptr->next; + + free(request->json_chunks->data); + free(request->json_chunks); + request->json_chunks = chunk_ptr; + } + + weechat_printf( + request->workspace->buffer, + _("%s%s: got response: %s"), + weechat_prefix("network"), SLACK_PLUGIN_NAME, + json_string); + + response = json_tokener_parse(json_string); + ok = json_object_object_get(response, "ok"); + if (!json_valid(ok, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + if(json_object_get_boolean(ok)) + { + members = json_object_object_get(response, "members"); + if (!json_valid(members, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + for (i = json_object_array_length(members); i > 0; i--) + { + user = json_object_array_get_idx(members, i - 1); + if (!json_valid(user, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + id = json_object_object_get(user, "id"); + if (!json_valid(id, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + name = json_object_object_get(user, "name"); + if (!json_valid(name, request->workspace)) + { + json_object_put(response); + free(json_string); + 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)); + } + } + else + { + error = json_object_object_get(response, "error"); + if (!json_valid(error, request->workspace)) + { + json_object_put(response); + free(json_string); + return 0; + } + + weechat_printf( + request->workspace->buffer, + _("%s%s: failed to retrieve users: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + json_object_get_string(error)); + } + + json_object_put(response); + free(json_string); + } + case LWS_CALLBACK_CLOSED_CLIENT_HTTP: + request->client_wsi = NULL; + lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ + break; + + default: + break; + } + + return lws_callback_http_dummy(wsi, reason, user, in, len); +} + +static const struct lws_protocols protocols[] = { + { + "http", + callback_http, + 0, + 0, + }, + { NULL, NULL, 0, 0 } +}; + +struct t_slack_request *slack_request_users_list( + struct t_slack_workspace *workspace, + const char *token, const char *cursor) +{ + struct t_slack_request *request; + struct lws_context_creation_info ctxinfo; + struct lws_client_connect_info ccinfo; + + request = slack_request_alloc(workspace); + + size_t urilen = snprintf(NULL, 0, endpoint, token, cursor) + 1; + request->uri = malloc(urilen); + snprintf(request->uri, urilen, endpoint, token, cursor); + + memset(&ctxinfo, 0, sizeof(ctxinfo)); /* otherwise uninitialized garbage */ + ctxinfo.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; + ctxinfo.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ + ctxinfo.protocols = protocols; + + request->context = lws_create_context(&ctxinfo); + if (!request->context) + { + weechat_printf( + workspace->buffer, + _("%s%s: error connecting to slack: lws init failed"), + weechat_prefix("error"), SLACK_PLUGIN_NAME); + return NULL; + } + else + { + weechat_printf( + workspace->buffer, + _("%s%s: contacting slack.com:443"), + weechat_prefix("network"), SLACK_PLUGIN_NAME); + } + + memset(&ccinfo, 0, sizeof(ccinfo)); /* otherwise uninitialized garbage */ + ccinfo.context = request->context; + ccinfo.ssl_connection = LCCSCF_USE_SSL; + ccinfo.port = 443; + ccinfo.address = "slack.com"; + ccinfo.path = request->uri; + ccinfo.host = ccinfo.address; + ccinfo.origin = ccinfo.address; + ccinfo.method = "GET"; + ccinfo.protocol = protocols[0].name; + ccinfo.pwsi = &request->client_wsi; + ccinfo.userdata = request; + + lws_client_connect_via_info(&ccinfo); + + return request; +} diff --git a/request/slack-request-users-list.h b/request/slack-request-users-list.h new file mode 100644 index 0000000..4623c4b --- /dev/null +++ b/request/slack-request-users-list.h @@ -0,0 +1,8 @@ +#ifndef _SLACK_REQUEST_USERS_LIST_H_ +#define _SLACK_REQUEST_USERS_LIST_H_ + +struct t_slack_request *slack_request_users_list( + struct t_slack_workspace *workspace, + const char *token, const char *cursor); + +#endif /*SLACK_REQUEST_USERS_LIST_H*/ diff --git a/slack-api.c b/slack-api.c index b9510fa..ff92721 100644 --- a/slack-api.c +++ b/slack-api.c @@ -1,11 +1,37 @@ #include #include +#include #include #include "weechat-plugin.h" #include "slack.h" #include "slack-workspace.h" #include "slack-api.h" +#include "api/slack-api-hello.h" +#include "api/slack-api-error.h" + +struct stringcase +{ + const char *string; + int (*func)(struct t_slack_workspace *workspace, + json_object *message); +}; + +struct stringcase cases[] = +{ { "hello", slack_api_hello } +, { "error", slack_api_error } +}; + +static int stringcase_cmp(const void *p1, const void *p2) +{ + return strcasecmp(((struct stringcase*)p1)->string, ((struct stringcase*)p2)->string); +} + +void slack_api_init() +{ + size_t case_count = sizeof(cases) / sizeof(cases[0]); + qsort(cases, case_count, sizeof(struct stringcase), stringcase_cmp); +} static int callback_ws(struct lws* wsi, enum lws_callback_reasons reason, void *user, void* in, size_t len) @@ -59,6 +85,15 @@ static int callback_ws(struct lws* wsi, enum lws_callback_reasons reason, return -1; } + if (!slack_api_route_message(workspace, + json_object_get_string(type), response)) + { + json_object_put(response); + free(json_string); + return -1; + } + + json_object_put(response); free(json_string); } return 0; /* don't passthru */ @@ -157,3 +192,29 @@ void slack_api_connect(struct t_slack_workspace *workspace) lws_client_connect_via_info(&ccinfo); } + +int slack_api_route_message(struct t_slack_workspace *workspace, + const char *type, 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: %s"), + weechat_prefix("error"), SLACK_PLUGIN_NAME, + type); + return 1; + } +} diff --git a/slack-api.h b/slack-api.h index 6a0281b..249f975 100644 --- a/slack-api.h +++ b/slack-api.h @@ -1,6 +1,11 @@ #ifndef _SLACK_API_H_ #define _SLACK_API_H_ +void slack_api_init(); + void slack_api_connect(struct t_slack_workspace *workspace); +int slack_api_route_message(struct t_slack_workspace *workspace, + const char *type, json_object *message); + #endif /*SLACK_API_H*/ diff --git a/slack-buffer.c b/slack-buffer.c index 8fceb3d..40d49c0 100644 --- a/slack-buffer.c +++ b/slack-buffer.c @@ -2,13 +2,14 @@ #include "slack.h" #include "slack-buffer.h" #include "slack-workspace.h" +#include "slack-channel.h" void slack_buffer_get_workspace_and_channel(struct t_gui_buffer *buffer, - struct t_slack_workspace **workspace)//, - //struct t_slack_channel **channel) + struct t_slack_workspace **workspace, + struct t_slack_channel **channel) { struct t_slack_workspace *ptr_workspace; - //struct t_slack_channel *ptr_channel; + struct t_slack_channel *ptr_channel; if (!buffer) return; @@ -24,7 +25,6 @@ void slack_buffer_get_workspace_and_channel(struct t_gui_buffer *buffer, return; } - /* for (ptr_channel = ptr_workspace->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { @@ -37,22 +37,46 @@ void slack_buffer_get_workspace_and_channel(struct t_gui_buffer *buffer, return; } } - */ } /* no workspace or channel found */ } +int slack_buffer_nickcmp_cb(const void *pointer, void *data, + struct t_gui_buffer *buffer, + const char *nick1, + const char *nick2) +{ + struct t_slack_workspace *workspace; + + (void) data; + + if (pointer) + workspace = (struct t_slack_workspace *)pointer; + else + slack_buffer_get_workspace_and_channel(buffer, &workspace, NULL); + + if (workspace) + { + return weechat_strcasecmp(nick1, nick2); + } + else + { + return weechat_strcasecmp(nick1, nick2); + } +} + int slack_buffer_close_cb(const void *pointer, void *data, struct t_gui_buffer *buffer) { struct t_weechat_plugin *buffer_plugin = NULL; struct t_slack_workspace *ptr_workspace = NULL; + struct t_slack_channel *ptr_channel = NULL; buffer_plugin = weechat_buffer_get_pointer(buffer, "plugin"); if (buffer_plugin == weechat_slack_plugin) slack_buffer_get_workspace_and_channel(buffer, - &ptr_workspace);//, &ptr_channel); + &ptr_workspace, &ptr_channel); (void) pointer; (void) data; diff --git a/slack-buffer.h b/slack-buffer.h index 8ba6a03..7410ab2 100644 --- a/slack-buffer.h +++ b/slack-buffer.h @@ -1,6 +1,11 @@ #ifndef _SLACK_BUFFER_H_ #define _SLACK_BUFFER_H_ +int slack_buffer_nickcmp_cb(const void *pointer, void *data, + struct t_gui_buffer *buffer, + const char *nick1, + const char *nick2); + int slack_buffer_close_cb(const void *pointer, void *data, struct t_gui_buffer *buffer); diff --git a/slack-channel.c b/slack-channel.c new file mode 100644 index 0000000..4b855d6 --- /dev/null +++ b/slack-channel.c @@ -0,0 +1,311 @@ +#include +#include +#include + +#include "weechat-plugin.h" +#include "slack.h" +#include "slack-workspace.h" +#include "slack-channel.h" +#include "slack-input.h" +#include "slack-buffer.h" + +struct t_slack_channel *slack_channel_search(struct t_slack_workspace *workspace, + const char *id) +{ + struct t_slack_channel *ptr_channel; + + if (!workspace || !id) + return NULL; + + for (ptr_channel = workspace->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + if (weechat_strcasecmp(ptr_channel->id, id) == 0) + return ptr_channel; + } + + return NULL; +} + +struct t_gui_buffer *slack_channel_search_buffer(struct t_slack_workspace *workspace, + enum t_slack_channel_type type, + const char *name) +{ + struct t_hdata *hdata_buffer; + struct t_gui_buffer *ptr_buffer; + const char *ptr_type, *ptr_workspace_name, *ptr_channel_name; + + hdata_buffer = weechat_hdata_get("buffer"); + ptr_buffer = weechat_hdata_get_list(hdata_buffer, "gui_buffers"); + + while (ptr_buffer) + { + if (weechat_buffer_get_pointer(ptr_buffer, "plugin") == weechat_slack_plugin) + { + ptr_type = weechat_buffer_get_string(ptr_buffer, "localvar_type"); + ptr_workspace_name = weechat_buffer_get_string(ptr_buffer, + "localvar_server"); + ptr_channel_name = weechat_buffer_get_string(ptr_buffer, + "localvar_channel"); + if (ptr_type && ptr_type[0] + && ptr_workspace_name && ptr_workspace_name[0] + && ptr_channel_name && ptr_channel_name[0] + && ( (( (type == SLACK_CHANNEL_TYPE_CHANNEL) + || (type == SLACK_CHANNEL_TYPE_GROUP)) + && (strcmp(ptr_type, "channel") == 0)) + || (( (type == SLACK_CHANNEL_TYPE_MPIM) + || (type == SLACK_CHANNEL_TYPE_IM)) + && (strcmp(ptr_type, "private") == 0))) + && (strcmp(ptr_workspace_name, workspace->domain) == 0) + && (weechat_strcasecmp(ptr_channel_name, name) == 0)) + { + return ptr_buffer; + } + } + ptr_buffer = weechat_hdata_move(hdata_buffer, ptr_buffer, 1); + } + + return NULL; +} + +struct t_gui_buffer *slack_channel_create_buffer(struct t_slack_workspace *workspace, + enum t_slack_channel_type type, + const char *name) +{ + struct t_gui_buffer *ptr_buffer; + int buffer_created, current_buffer_number; + const char *short_name, *localvar_channel; + char buffer_name[256]; + + buffer_created = 0; + + snprintf(buffer_name, sizeof(buffer_name), + "%s.%s", workspace->domain, name); + + ptr_buffer = slack_channel_search_buffer(workspace, type, name); + if (ptr_buffer) + { + weechat_nicklist_remove_all(ptr_buffer); + } + else + { + current_buffer_number = weechat_buffer_get_integer( + weechat_current_buffer(), "number"); + + ptr_buffer = weechat_buffer_new(buffer_name, + &slack_input_data_cb, NULL, NULL, + &slack_buffer_close_cb, NULL, NULL); + if (!ptr_buffer) + return NULL; + + buffer_created = 1; + } + + if (buffer_created) + { + if (!weechat_buffer_get_integer(ptr_buffer, "short_name_is_set")) + weechat_buffer_set(ptr_buffer, "short_name", name); + } + else + { + short_name = weechat_buffer_get_string (ptr_buffer, "short_name"); + localvar_channel = weechat_buffer_get_string (ptr_buffer, + "localvar_channel"); + + if (!short_name || + (localvar_channel && (strcmp(localvar_channel, short_name) == 0))) + { + weechat_buffer_set (ptr_buffer, "short_name", name); + } + } + + weechat_buffer_set(ptr_buffer, "name", buffer_name); + weechat_buffer_set(ptr_buffer, "localvar_set_type", + (type == SLACK_CHANNEL_TYPE_IM || + type == SLACK_CHANNEL_TYPE_MPIM) ? "private" : "channel"); + weechat_buffer_set(ptr_buffer, "localvar_set_nick", workspace->nick); + weechat_buffer_set(ptr_buffer, "localvar_set_server", workspace->domain); + weechat_buffer_set(ptr_buffer, "localvar_set_channel", name); + + if (buffer_created) + { + (void) weechat_hook_signal_send ("logger_backlog", + WEECHAT_HOOK_SIGNAL_POINTER, + ptr_buffer); + weechat_buffer_set(ptr_buffer, "input_get_unknown_commands", "1"); + if (type != SLACK_CHANNEL_TYPE_IM) + { + weechat_buffer_set(ptr_buffer, "nicklist", "1"); + weechat_buffer_set(ptr_buffer, "nicklist_display_groups", "0"); + weechat_buffer_set_pointer(ptr_buffer, "nicklist_callback", + &slack_buffer_nickcmp_cb); + weechat_buffer_set_pointer(ptr_buffer, "nicklist_callback_pointer", + workspace); + } + + weechat_buffer_set(ptr_buffer, "highlight_words_add", + workspace->nick); + weechat_buffer_set(ptr_buffer, "highlight_tags_restrict", + "slack_message"); + } + + return ptr_buffer; +} + +struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace, + enum t_slack_channel_type type, + const char *id, const char *name) +{ + struct t_slack_channel *new_channel, *ptr_channel; + struct t_gui_buffer *ptr_buffer; + + if (!workspace || !id) + return NULL; + + ptr_channel = slack_channel_search(workspace, id); + if (ptr_channel) + { + return ptr_channel; + } + + ptr_buffer = slack_channel_create_buffer(workspace, type, name); + if (!ptr_buffer) + return NULL; + + if ((new_channel = malloc(sizeof(*new_channel))) == NULL) + return NULL; + + new_channel->type = type; + new_channel->id = strdup(id); + new_channel->name = strdup(name); + new_channel->created = 0; + + new_channel->is_general = 0; + new_channel->name_normalized = NULL; + new_channel->is_shared = 0; + new_channel->is_org_shared = 0; + new_channel->is_member = 0; + + new_channel->topic.value = NULL; + new_channel->topic.creator = NULL; + new_channel->topic.last_set = 0; + new_channel->purpose.value = NULL; + new_channel->purpose.creator = NULL; + new_channel->purpose.last_set = 0; + new_channel->is_archived = 0; + + new_channel->creator = NULL; + new_channel->last_read = 0.0; + new_channel->unread_count = 0; + new_channel->unread_count_display = 0; + + new_channel->is_user_deleted = 0; + + new_channel->members = NULL; + new_channel->last_member = NULL; + 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; + if (workspace->last_channel) + (workspace->last_channel)->next_channel = new_channel; + workspace->last_channel = new_channel; + + return new_channel; +} + +void slack_channel_member_free(struct t_slack_channel *channel, + struct t_slack_channel_member *member) +{ + struct t_slack_channel_member *new_members; + + if (!channel || !member) + return; + + /* remove member from members list */ + if (channel->last_member == member) + channel->last_member = member->prev_member; + if (member->prev_member) + { + (member->prev_member)->next_member = member->next_member; + new_members = channel->members; + } + else + new_members = member->next_member; + + if (member->next_member) + (member->next_member)->prev_member = member->prev_member; + + /* free member data */ + if (member->id) + free(member->id); + + free(member); + + channel->members = new_members; +} + +void slack_channel_member_free_all(struct t_slack_channel *channel) +{ + while (channel->members) + slack_channel_member_free(channel, channel->members); +} + +void slack_channel_free(struct t_slack_workspace *workspace, + struct t_slack_channel *channel) +{ + struct t_slack_channel *new_channels; + + if (!workspace || !channel) + return; + + /* remove channel from channels list */ + if (workspace->last_channel == channel) + workspace->last_channel = channel->prev_channel; + if (channel->prev_channel) + { + (channel->prev_channel)->next_channel = channel->next_channel; + new_channels = workspace->channels; + } + else + new_channels = channel->next_channel; + + if (channel->next_channel) + (channel->next_channel)->prev_channel = channel->prev_channel; + + /* free linked lists */ + slack_channel_member_free_all(channel); + + /* free channel data */ + if (channel->id) + free(channel->id); + if (channel->name) + free(channel->name); + if (channel->name_normalized) + free(channel->name_normalized); + if (channel->topic.value) + free(channel->topic.value); + if (channel->topic.creator) + free(channel->topic.creator); + if (channel->purpose.value) + free(channel->purpose.value); + if (channel->purpose.creator) + free(channel->purpose.creator); + if (channel->creator) + free(channel->creator); + if (channel->buffer_as_string) + free (channel->buffer_as_string); + + free(channel); + + workspace->channels = new_channels; +} + +void slack_channel_free_all(struct t_slack_workspace *workspace) +{ + while (workspace->channels) + slack_channel_free(workspace, workspace->channels); +} diff --git a/slack-channel.h b/slack-channel.h new file mode 100644 index 0000000..b9b46b5 --- /dev/null +++ b/slack-channel.h @@ -0,0 +1,80 @@ +#ifndef _SLACK_CHANNEL_H_ +#define _SLACK_CHANNEL_H_ + +enum t_slack_channel_type +{ + SLACK_CHANNEL_TYPE_CHANNEL, + SLACK_CHANNEL_TYPE_GROUP, + SLACK_CHANNEL_TYPE_MPIM, + SLACK_CHANNEL_TYPE_IM, +}; + +struct t_slack_channel_member +{ + char *id; + + struct t_slack_channel_member *prev_member; + struct t_slack_channel_member *next_member; +}; + +struct t_slack_channel_topic +{ + char *value; + char *creator; + int last_set; +}; + +struct t_slack_channel_purpose +{ + char *value; + char *creator; + int last_set; +}; + +struct t_slack_channel +{ + enum t_slack_channel_type type; + char *id; + char *name; + int created; + + /* channel */ + int is_general; + char *name_normalized; + int is_shared; + int is_org_shared; + int is_member; + + /* group */ + struct t_slack_channel_topic topic; + struct t_slack_channel_purpose purpose; + int is_archived; + + /* mpim */ + char *creator; + double last_read; + int unread_count; + int unread_count_display; + + /* im */ + int is_user_deleted; + + struct t_slack_channel_member *members; + struct t_slack_channel_member *last_member; + struct t_gui_buffer *buffer; + char *buffer_as_string; + + struct t_slack_channel *prev_channel; + struct t_slack_channel *next_channel; +}; + +struct t_slack_channel *slack_channel_search(struct t_slack_workspace *workspace, + const char *id); + +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); + +#endif /*SLACK_CHANNEL_H*/ diff --git a/slack-request.c b/slack-request.c new file mode 100644 index 0000000..6db1816 --- /dev/null +++ b/slack-request.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +#include "weechat-plugin.h" +#include "slack.h" +#include "slack-workspace.h" +#include "slack-request.h" + +struct t_slack_request *slack_request_alloc( + struct t_slack_workspace *workspace) +{ + struct t_slack_request *request; + + request = malloc(sizeof(struct t_slack_request)); + memset(request, 0, sizeof(struct t_slack_request)); + + request->workspace = workspace; + + return request; +} diff --git a/slack-request.h b/slack-request.h new file mode 100644 index 0000000..21abf8b --- /dev/null +++ b/slack-request.h @@ -0,0 +1,19 @@ +#ifndef _SLACK_REQUEST_H_ +#define _SLACK_REQUEST_H_ + +struct t_slack_request +{ + struct t_slack_workspace *workspace; + + 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 *slack_request_alloc( + struct t_slack_workspace *workspace); + +#endif /*SLACK_REQUEST_H*/ diff --git a/slack-user.c b/slack-user.c new file mode 100644 index 0000000..c093b97 --- /dev/null +++ b/slack-user.c @@ -0,0 +1,151 @@ +#include +#include + +#include "weechat-plugin.h" +#include "slack.h" +#include "slack-workspace.h" +#include "slack-user.h" + +struct t_slack_user *slack_user_search(struct t_slack_workspace *workspace, + const char *id) +{ + struct t_slack_user *ptr_user; + + if (!workspace || !id) + return NULL; + + for (ptr_user = workspace->users; ptr_user; + ptr_user = ptr_user->next_user) + { + if (weechat_strcasecmp(ptr_user->id, id) == 0) + return ptr_user; + } + + return NULL; +} + +struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace, + const char *id) +{ + struct t_slack_user *new_user, *ptr_user; + + if (!workspace || !id) + return NULL; + + ptr_user = slack_user_search(workspace, id); + if (ptr_user) + { + return ptr_user; + } + + if ((new_user = malloc(sizeof(*new_user))) == NULL) + return NULL; + + new_user->prev_user = workspace->last_user; + (workspace->last_user)->next_user = new_user; + workspace->last_user = new_user; + + new_user->id = strdup(id); + new_user->name = NULL; + new_user->team_id = NULL; + new_user->real_name = NULL; + new_user->colour = NULL; + new_user->deleted = 0; + + new_user->tz = NULL; + new_user->tz_label = NULL; + new_user->tz_offset = 0; + new_user->locale = NULL; + + new_user->profile.avatar_hash = NULL; + 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.real_name_normalized = NULL; + new_user->profile.email = NULL; + new_user->profile.team = NULL; + new_user->updated = 0; + + new_user->is_admin = 0; + new_user->is_owner = 0; + new_user->is_primary_owner = 0; + new_user->is_restricted = 0; + new_user->is_ultra_restricted = 0; + new_user->is_bot = 0; + new_user->is_stranger = 0; + new_user->is_app_user = 0; + new_user->has_2fa = 0; + + new_user->prev_user = NULL; + new_user->next_user = NULL; + + return new_user; +} + +void slack_user_free(struct t_slack_workspace *workspace, + struct t_slack_user *user) +{ + struct t_slack_user *new_users; + + if (!workspace || !user) + return; + + /* remove user from users list */ + if (workspace->last_user == user) + workspace->last_user = user->prev_user; + if (user->prev_user) + { + (user->prev_user)->next_user = user->next_user; + new_users = workspace->users; + } + else + new_users = user->next_user; + + if (user->next_user) + (user->next_user)->prev_user = user->prev_user; + + /* free user data */ + if (user->id) + free(user->id); + if (user->name) + free(user->name); + if (user->team_id) + free(user->team_id); + if (user->real_name) + free(user->real_name); + if (user->colour) + free(user->colour); + if (user->tz) + free(user->tz); + if (user->tz_label) + free(user->tz_label); + if (user->locale) + free(user->locale); + if (user->profile.avatar_hash) + free(user->profile.avatar_hash); + if (user->profile.status_text) + free(user->profile.status_text); + if (user->profile.status_emoji) + free(user->profile.status_emoji); + if (user->profile.real_name) + free(user->profile.real_name); + if (user->profile.display_name) + free(user->profile.display_name); + if (user->profile.real_name_normalized) + free(user->profile.real_name_normalized); + if (user->profile.email) + free(user->profile.email); + if (user->profile.team) + free(user->profile.team); + + free(user); + + workspace->users = new_users; +} + +void slack_user_free_all(struct t_slack_workspace *workspace) +{ + while (workspace->users) + slack_user_free(workspace, workspace->users); +} diff --git a/slack-user.h b/slack-user.h new file mode 100644 index 0000000..7bdf5a8 --- /dev/null +++ b/slack-user.h @@ -0,0 +1,55 @@ +#ifndef _SLACK_USER_H_ +#define _SLACK_USER_H_ + +struct t_slack_user_profile +{ + char *avatar_hash; + char *status_text; + char *status_emoji; + char *real_name; + char *display_name; + char *real_name_normalized; + char *email; + char *team; +}; + +struct t_slack_user +{ + char *id; + char *name; + char *team_id; + char *real_name; + char *colour; + + int deleted; + char *tz; + char *tz_label; + int tz_offset; + char *locale; + + struct t_slack_user_profile profile; + int updated; + + int is_admin; + int is_owner; + int is_primary_owner; + int is_restricted; + int is_ultra_restricted; + int is_bot; + int is_stranger; + int is_app_user; + int has_2fa; + + struct t_slack_user *prev_user; + struct t_slack_user *next_user; +}; + +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); + +void slack_channel_free_all(struct t_slack_workspace *workspace); + +#endif /*SLACK_USER_H*/ diff --git a/slack-workspace.c b/slack-workspace.c index 32fcf30..fee7b14 100644 --- a/slack-workspace.c +++ b/slack-workspace.c @@ -12,6 +12,9 @@ #include "slack-input.h" #include "slack-workspace.h" #include "slack-api.h" +#include "slack-request.h" +#include "slack-user.h" +#include "slack-channel.h" struct t_slack_workspace *slack_workspaces = NULL; struct t_slack_workspace *last_slack_workspace = NULL; @@ -21,7 +24,7 @@ char *slack_workspace_options[SLACK_WORKSPACE_NUM_OPTIONS][2] = }; static const char *const endpoint = "/api/rtm.connect?" - "token=%s&batch_presence_aware=true&presence_sub=false"; + "token=%s&batch_presence_aware=true&presence_sub=false&"; static inline int json_valid(json_object *object, struct t_slack_workspace *workspace) { @@ -222,7 +225,6 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, free(json_string); return 0; } - workspace->ws_url = strdup(json_object_get_string(url)); } else @@ -367,12 +369,17 @@ struct t_slack_workspace *slack_workspace_alloc(const char *domain) new_workspace->client_wsi = NULL; new_workspace->context = NULL; new_workspace->json_chunks = NULL; + new_workspace->requests = NULL; new_workspace->user = NULL; new_workspace->nick = NULL; new_workspace->buffer = NULL; new_workspace->buffer_as_string = NULL; + new_workspace->users = NULL; + new_workspace->last_user = NULL; + new_workspace->channels = NULL; + new_workspace->last_channel = NULL; /* create options with null value */ for (i = 0; i < SLACK_WORKSPACE_NUM_OPTIONS; i++) @@ -453,10 +460,8 @@ void slack_workspace_free_data(struct t_slack_workspace *workspace) free(workspace->uri); if (workspace->ws_url) free(workspace->ws_url); - if (workspace->client_wsi) - free(workspace->client_wsi); if (workspace->context) - free(workspace->context); + lws_context_destroy(workspace->context); while (workspace->json_chunks) { struct t_json_chunk *chunk_ptr = workspace->json_chunks->next; @@ -465,6 +470,13 @@ void slack_workspace_free_data(struct t_slack_workspace *workspace) free(workspace->json_chunks); workspace->json_chunks = chunk_ptr; } + while (workspace->requests) + { + struct t_slack_request *request_ptr = workspace->requests->next; + + free(workspace->requests); + workspace->requests = request_ptr; + } if (workspace->user) free(workspace->user); @@ -473,6 +485,9 @@ void slack_workspace_free_data(struct t_slack_workspace *workspace) if (workspace->buffer_as_string) free(workspace->buffer_as_string); + + slack_channel_free_all(workspace); + slack_user_free_all(workspace); } void slack_workspace_free(struct t_slack_workspace *workspace) @@ -638,7 +653,7 @@ struct t_gui_buffer *slack_workspace_create_buffer(struct t_slack_workspace *wor char buffer_name[256], charset_modifier[256]; snprintf(buffer_name, sizeof(buffer_name), - "slack.%s", workspace->domain); + "workspace.%s", workspace->domain); workspace->buffer = weechat_buffer_new(buffer_name, &slack_input_data_cb, NULL, NULL, &slack_buffer_close_cb, NULL, NULL); @@ -651,12 +666,19 @@ struct t_gui_buffer *slack_workspace_create_buffer(struct t_slack_workspace *wor weechat_buffer_set(workspace->buffer, "localvar_set_server", workspace->domain); weechat_buffer_set(workspace->buffer, "localvar_set_channel", workspace->domain); snprintf(charset_modifier, sizeof (charset_modifier), - "slack.%s", workspace->domain); + "workspace.%s", workspace->domain); weechat_buffer_set(workspace->buffer, "localvar_set_charset_modifier", charset_modifier); weechat_buffer_set(workspace->buffer, "title", (workspace->name) ? workspace->name : ""); + weechat_buffer_set(workspace->buffer, "nicklist", "1"); + weechat_buffer_set(workspace->buffer, "nicklist_display_groups", "0"); + weechat_buffer_set_pointer(workspace->buffer, "nicklist_callback", + &slack_buffer_nickcmp_cb); + weechat_buffer_set_pointer(workspace->buffer, "nicklist_callback_pointer", + workspace); + return workspace->buffer; } @@ -749,6 +771,7 @@ int slack_workspace_connect(struct t_slack_workspace *workspace) int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_calls) { struct t_slack_workspace *ptr_workspace; + struct t_slack_request *ptr_request; /* make C compiler happy */ (void) pointer; @@ -761,6 +784,25 @@ int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_call if (!ptr_workspace->is_connected) continue; + for (ptr_request = ptr_workspace->requests; ptr_request; + ptr_request = ptr_request->next) + { + if (ptr_request->client_wsi) + { + lws_service(ptr_request->context, 0); + } + else if (ptr_request->context) + { + lws_context_destroy(ptr_request->context); + ptr_request->context = NULL; + if (ptr_request->uri) + { + free(ptr_request->uri); + ptr_request->uri = NULL; + } + } + } + if (ptr_workspace->client_wsi) { lws_service(ptr_workspace->context, 0); @@ -785,3 +827,11 @@ int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_call return WEECHAT_RC_OK; } + +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; +} diff --git a/slack-workspace.h b/slack-workspace.h index 216eeb7..8ce6f53 100644 --- a/slack-workspace.h +++ b/slack-workspace.h @@ -34,12 +34,17 @@ struct t_slack_workspace struct lws *client_wsi; struct lws_context *context; struct t_json_chunk *json_chunks; + struct t_slack_request *requests; char *user; char *nick; struct t_gui_buffer *buffer; char *buffer_as_string; + struct t_slack_user *users; + struct t_slack_user *last_user; + struct t_slack_channel *channels; + struct t_slack_channel *last_channel; struct t_slack_workspace *prev_workspace; struct t_slack_workspace *next_workspace; }; @@ -59,5 +64,7 @@ void slack_workspace_disconnect_all(); void slack_workspace_close_connection(struct t_slack_workspace *workspace); int slack_workspace_connect(struct t_slack_workspace *workspace); int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_calls); +void slack_workspace_register_request(struct t_slack_workspace *workspace, + struct t_slack_request *request); #endif /*SLACK_WORKSPACE_H*/ diff --git a/slack.c b/slack.c index 528e4b1..c1cee92 100644 --- a/slack.c +++ b/slack.c @@ -2,12 +2,14 @@ #include #include #include +#include #include "weechat-plugin.h" #include "slack.h" #include "slack-config.h" #include "slack-command.h" #include "slack-workspace.h" +#include "slack-api.h" WEECHAT_PLUGIN_NAME(SLACK_PLUGIN_NAME); @@ -15,7 +17,7 @@ WEECHAT_PLUGIN_DESCRIPTION(N_("Slack (slack.com) protocol")); WEECHAT_PLUGIN_AUTHOR("Tony Olagbaiye "); WEECHAT_PLUGIN_VERSION(SLACK_PLUGIN_VERSION); WEECHAT_PLUGIN_LICENSE("MPL2"); -WEECHAT_PLUGIN_PRIORITY(6000); +WEECHAT_PLUGIN_PRIORITY(5500); struct t_weechat_plugin *weechat_slack_plugin = NULL; @@ -52,6 +54,8 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) slack_command_init(); + slack_api_init(); + slack_hook_timer = weechat_hook_timer(1 * 1000, 0, 0, &slack_workspace_timer_cb, NULL, NULL);