Server buffer creation

v1
Tony Olagbaiye 7 years ago
parent 4fde364512
commit 47a8e86a34

@ -1,24 +1,28 @@
CC=clang CC=clang
CXX=clang++ CXX=clang++
RM=rm -f RM=rm -f
CFLAGS=-fPIC -std=gnu99 -g -Wall -Wextra -Werror-implicit-function-declaration -I libwebsockets/include -I json-c CFLAGS=-fPIC -std=gnu99 -g -Wall -Wextra -Werror-implicit-function-declaration -Wno-missing-field-initializers -I libwebsockets/include -I json-c
LDFLAGS=-shared -g LDFLAGS=-shared -g
LDLIBS=-lssl LDLIBS=-lssl
SRCS=slack.c \ SRCS=slack.c \
slack-api.c \
slack-buffer.c \
slack-config.c \ slack-config.c \
slack-command.c \ slack-command.c \
slack-input.c \
slack-oauth.c \ slack-oauth.c \
slack-teaminfo.c \
slack-workspace.c slack-workspace.c
OBJS=$(subst .c,.o,$(SRCS)) libwebsockets/lib/libwebsockets.a json-c/libjson-c.a OBJS=$(subst .c,.o,$(SRCS)) libwebsockets/lib/libwebsockets.a json-c/libjson-c.a
all: weechat-slack all: libwebsockets/lib/libwebsockets.a json-c/libjson-c.a weechat-slack
weechat-slack: $(OBJS) weechat-slack: $(OBJS)
$(CC) $(LDFLAGS) -o slack.so $(OBJS) $(LDLIBS) $(CC) $(LDFLAGS) -o slack.so $(OBJS) $(LDLIBS)
libwebsockets/lib/libwebsockets.a: libwebsockets/lib/libwebsockets.a:
cd libwebsockets && cmake -DLWS_STATIC_PIC=ON -DLWS_WITH_SHARED=OFF -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITH_LIBEV=OFF -DLWS_WITH_LIBUV=OFF -DLWS_WITH_LIBEVENT=OFF . cd libwebsockets && cmake -DLWS_STATIC_PIC=ON -DLWS_WITH_SHARED=OFF -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITH_LIBEV=OFF -DLWS_WITH_LIBUV=OFF -DLWS_WITH_LIBEVENT=OFF -DCMAKE_BUILD_TYPE=DEBUG .
$(MAKE) -C libwebsockets $(MAKE) -C libwebsockets
json-c/libjson-c.a: json-c/libjson-c.a:

@ -1 +1 @@
Subproject commit 91a47f4fab4d74f49a341ce22954a563f6544446 Subproject commit f1c56bc233a5f05c01c93a5c250a31b4d309ecac

@ -0,0 +1,158 @@
#include <libwebsockets.h>
#include <string.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
#include "slack-api.h"
static int callback_ws(struct lws* wsi, enum lws_callback_reasons reason,
void *user, void* in, size_t len)
{
struct t_slack_workspace *workspace = (struct t_slack_workspace *)user;
(void) wsi;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
workspace->buffer,
_("%s%s: error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
in ? (char *)in : "(null)");
workspace->client_wsi = NULL;
break;
case LWS_CALLBACK_CLIENT_ESTABLISHED:
weechat_printf(
workspace->buffer,
_("%s%s: waiting for hello..."),
weechat_prefix("network"), SLACK_PLUGIN_NAME);
break;
/* chunks of chunked content, with header removed */
case LWS_CALLBACK_CLIENT_RECEIVE:
weechat_printf(
workspace->buffer,
_("%s%s: received data: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME,
(const char *)in);
{
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 (workspace->json_chunks)
{
for (last_chunk = workspace->json_chunks; last_chunk->next;
last_chunk = last_chunk->next);
last_chunk->next = new_chunk;
}
else
{
workspace->json_chunks = new_chunk;
}
}
return 0; /* don't passthru */
case LWS_CALLBACK_CLIENT_WRITEABLE:
weechat_printf(
workspace->buffer,
_("%s%s: websocket is writeable"),
weechat_prefix("network"), SLACK_PLUGIN_NAME);
break;
case LWS_CALLBACK_CLOSED:
workspace->client_wsi = NULL;
workspace->disconnected = 1;
/* start reconnect timer */
break;
default:
break;
}
return lws_callback_http_dummy(wsi, reason, user, in, len);
}
static const struct lws_protocols protocols[] = {
{
"default",
callback_ws,
0,
0,
},
{ NULL, NULL, 0, 0 }
};
void slack_api_connect(struct t_slack_workspace *workspace)
{
struct lws_context_creation_info ctxinfo;
struct lws_client_connect_info ccinfo;
const char *url_protocol, *url_path;
char path[512];
memset(&ctxinfo, 0, sizeof(ctxinfo));
memset(&ccinfo, 0, sizeof(ccinfo));
ccinfo.port = 443;
if (lws_parse_uri(workspace->ws_url,
&url_protocol, &ccinfo.address,
&ccinfo.port, &url_path))
{
weechat_printf(
workspace->buffer,
_("%s%s: error connecting to slack: bad websocket uri"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
path[0] = '/';
strncpy(path + 1, url_path, sizeof(path) - 2);
path[sizeof(path) - 1] = '\0';
ccinfo.path = path;
ctxinfo.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
ctxinfo.port = CONTEXT_PORT_NO_LISTEN;
ctxinfo.protocols = protocols;
ctxinfo.uid = -1;
ctxinfo.gid = -1;
workspace->context = lws_create_context(&ctxinfo);
if (!workspace->context)
{
weechat_printf(
workspace->buffer,
_("%s%s: error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: connecting to %s://%s:%d%s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME,
url_protocol, ccinfo.address, ccinfo.port, path);
}
ccinfo.context = workspace->context;
ccinfo.ssl_connection = LCCSCF_USE_SSL;
ccinfo.host = ccinfo.address;
ccinfo.origin = ccinfo.address;
ccinfo.ietf_version_or_minus_one = -1;
ccinfo.protocol = protocols[0].name;
ccinfo.pwsi = &workspace->client_wsi;
ccinfo.userdata = workspace;
lws_client_connect_via_info(&ccinfo);
}

@ -0,0 +1,6 @@
#ifndef _SLACK_API_H_
#define _SLACK_API_H_
void slack_api_connect(struct t_slack_workspace *workspace);
#endif /*SLACK_API_H*/

@ -0,0 +1,73 @@
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-buffer.h"
#include "slack-workspace.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 *ptr_workspace;
//struct t_slack_channel *ptr_channel;
if (!buffer)
return;
/* look for a workspace or channel using this buffer */
for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace)
{
if (ptr_workspace->buffer == buffer)
{
if (workspace)
*workspace = ptr_workspace;
return;
}
/*
for (ptr_channel = ptr_workspace->channels; ptr_channel;
ptr_channel = ptr_channel->next_channel)
{
if (ptr_channel->buffer == buffer)
{
if (workspace)
*workspace = ptr_workspace;
if (channel)
*channel = ptr_channel;
return;
}
}
*/
}
/* no workspace or channel found */
}
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;
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);
(void) pointer;
(void) data;
(void) buffer;
if (ptr_workspace)
{
if (!ptr_workspace->disconnected)
{
//slack_command_quit_workspace(ptr_workspace, NULL);
slack_workspace_disconnect(ptr_workspace, 0, 0);
}
ptr_workspace->buffer = NULL;
}
return WEECHAT_RC_OK;
}

@ -0,0 +1,7 @@
#ifndef _SLACK_BUFFER_H_
#define _SLACK_BUFFER_H_
int slack_buffer_close_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer);
#endif /*SLACK_BUFFER_H*/

@ -5,6 +5,7 @@
#include "slack.h" #include "slack.h"
#include "slack-command.h" #include "slack-command.h"
#include "slack-oauth.h" #include "slack-oauth.h"
#include "slack-teaminfo.h"
#include "slack-workspace.h" #include "slack-workspace.h"
void slack_command_display_workspace(struct t_slack_workspace *workspace) void slack_command_display_workspace(struct t_slack_workspace *workspace)
@ -17,10 +18,15 @@ void slack_command_display_workspace(struct t_slack_workspace *workspace)
num_pv = 0;//slack_workspace_get_pv_count(workspace); num_pv = 0;//slack_workspace_get_pv_count(workspace);
weechat_printf( weechat_printf(
NULL, NULL,
" %s %s%s %s[%s%s%s]%s, %d %s, %d pv", " %s %s%s%s.slack.com %s(%s%s%s) [%s%s%s]%s, %d %s, %d pv",
(workspace->is_connected) ? "*" : " ", (workspace->is_connected) ? "*" : " ",
weechat_color("chat_workspace"), weechat_color("chat_server"),
workspace->name, workspace->domain,
weechat_color("reset"),
weechat_color("chat_delimiters"),
weechat_color("chat_server"),
(workspace->name) ?
workspace->name : "???",
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("reset"), weechat_color("reset"),
(workspace->is_connected) ? (workspace->is_connected) ?
@ -35,9 +41,15 @@ void slack_command_display_workspace(struct t_slack_workspace *workspace)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
" %s%s%s", " %s%s%s.slack.com %s(%s%s%s)%s",
weechat_color("chat_workspace"), weechat_color("chat_server"),
workspace->name, workspace->domain,
weechat_color("reset"),
weechat_color("chat_delimiters"),
weechat_color("chat_server"),
(workspace->name) ?
workspace->name : "???",
weechat_color("chat_delimiters"),
weechat_color("reset")); weechat_color("reset"));
} }
} }
@ -94,8 +106,56 @@ void slack_command_workspace_list(int argc, char **argv)
} }
} }
void slack_command_add_workspace(char *token) void slack_command_add_workspace(struct t_slack_teaminfo *slack_teaminfo)
{
struct t_slack_workspace *workspace;
workspace = slack_workspace_casesearch(slack_teaminfo->domain);
if (workspace)
{
weechat_printf(
NULL,
_("%s%s: workspace \"%s\" already exists, can't add it!"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
slack_teaminfo->domain);
return;
}
workspace = slack_workspace_alloc(slack_teaminfo->domain);
if (!workspace)
{
weechat_printf(
NULL,
_("%s%s: unable to add workspace"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
workspace->id = strdup(slack_teaminfo->id);
workspace->name = strdup(slack_teaminfo->name);
weechat_config_option_set(workspace->options[SLACK_WORKSPACE_OPTION_TOKEN],
slack_teaminfo->token, 1);
weechat_printf (
NULL,
_("%s: workspace %s%s%s.slack.com %s(%s%s%s)%s added"),
SLACK_PLUGIN_NAME,
weechat_color("chat_server"),
workspace->domain,
weechat_color("reset"),
weechat_color("chat_delimiters"),
weechat_color("chat_server"),
workspace->name,
weechat_color("chat_delimiters"),
weechat_color("reset"));
free_teaminfo(slack_teaminfo);
}
void slack_command_fetch_workspace(char *token)
{ {
slack_teaminfo_fetch(token, &slack_command_add_workspace);
free(token); free(token);
} }
@ -107,13 +167,13 @@ void slack_command_workspace_register(int argc, char **argv)
{ {
code = argv[2]; code = argv[2];
if (weechat_strncasecmp("xoxp", code, 4) == 0) if (strncmp("xoxp", code, 4) == 0)
{ {
slack_command_add_workspace(strdup(code)); slack_command_fetch_workspace(strdup(code));
} }
else else
{ {
slack_oauth_request_token(code, &slack_command_add_workspace); slack_oauth_request_token(code, &slack_command_fetch_workspace);
} }
} }
else else
@ -121,7 +181,7 @@ void slack_command_workspace_register(int argc, char **argv)
weechat_printf(NULL, weechat_printf(NULL,
_("\n#### Retrieving a Slack token via OAUTH ####\n" _("\n#### Retrieving a Slack token via OAUTH ####\n"
"1) Paste this into a browser: https://slack.com/oauth/authorize?client_id=%s&scope=client\n" "1) Paste this into a browser: https://slack.com/oauth/authorize?client_id=%s&scope=client\n"
"2) Select the team you wish to access from wee-slack in your browser.\n" "2) Select the team you wish to access from weechat in your browser.\n"
"3) Click \"Authorize\" in the browser **IMPORTANT: the redirect will fail, this is expected**\n" "3) Click \"Authorize\" in the browser **IMPORTANT: the redirect will fail, this is expected**\n"
"4) Copy the \"code\" portion of the URL to your clipboard\n" "4) Copy the \"code\" portion of the URL to your clipboard\n"
"5) Return to weechat and run `/slack register [code]`\n"), "5) Return to weechat and run `/slack register [code]`\n"),
@ -129,8 +189,109 @@ void slack_command_workspace_register(int argc, char **argv)
} }
} }
int slack_command_connect_workspace(struct t_slack_workspace *workspace)
{
if (!workspace)
return 0;
if (workspace->is_connected)
{
weechat_printf(
NULL,
_("%s%s: already connected to workspace \"%s\"!"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
workspace->domain);
}
slack_workspace_connect(workspace);
return 1;
}
int slack_command_workspace_connect(int argc, char **argv)
{
int i, nb_connect, connect_ok;
struct t_slack_workspace *ptr_workspace;
(void) argc;
(void) argv;
connect_ok = 1;
nb_connect = 0;
for (i = 2; i < argc; i++)
{
nb_connect++;
ptr_workspace = slack_workspace_search(argv[i]);
if (ptr_workspace)
{
if (!slack_command_connect_workspace(ptr_workspace))
{
connect_ok = 0;
}
}
else
{
weechat_printf(
NULL,
_("%s%s: workspace not found \"%s\" "
"(register first with: /slack register)"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
argv[i]);
}
}
return (connect_ok) ? WEECHAT_RC_OK : WEECHAT_RC_ERROR;
}
void slack_command_workspace_delete(int argc, char **argv) void slack_command_workspace_delete(int argc, char **argv)
{ {
struct t_slack_workspace *workspace;
char *workspace_domain;
if (argc < 3)
{
weechat_printf(
NULL,
_("%sToo few arguments for command\"%s %s\" "
"(help on command: /help %s)"),
weechat_prefix("error"),
argv[0], argv[1], argv[0] + 1);
return;
}
workspace = slack_workspace_search(argv[2]);
if (!workspace)
{
weechat_printf(
NULL,
_("%s%s: workspace \"%s\" not found for \"%s\" command"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
argv[2], "slack delete");
return;
}
if (workspace->is_connected)
{
weechat_printf(
NULL,
_("%s%s: you cannot delete workspace \"%s\" because you"
"are connected. Try \"/slack disconnect %s\" first."),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
argv[2], argv[2]);
return;
}
workspace_domain = strdup(workspace->domain);
slack_workspace_free(workspace);
weechat_printf (
NULL,
_("%s: workspace %s%s%s has been deleted"),
SLACK_PLUGIN_NAME,
weechat_color("chat_server"),
(workspace_domain) ? workspace_domain : "???",
weechat_color("reset"));
if (workspace_domain)
free(workspace_domain);
} }
int slack_command_slack(const void *pointer, void *data, int slack_command_slack(const void *pointer, void *data,
@ -142,20 +303,26 @@ int slack_command_slack(const void *pointer, void *data,
(void) data; (void) data;
(void) buffer; (void) buffer;
if (argc > 1) if (argc <= 1 || weechat_strcasecmp(argv[1], "list") == 0)
{
if (weechat_strcasecmp(argv[1], "list") == 0)
{ {
slack_command_workspace_list(argc, argv); slack_command_workspace_list(argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
if (argc > 1)
{
if (weechat_strcasecmp(argv[1], "register") == 0) if (weechat_strcasecmp(argv[1], "register") == 0)
{ {
slack_command_workspace_register(argc, argv); slack_command_workspace_register(argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
if (weechat_strcasecmp(argv[1], "connect") == 0)
{
slack_command_workspace_connect(argc, argv);
return WEECHAT_RC_OK;
}
if (weechat_strcasecmp(argv[1], "delete") == 0) if (weechat_strcasecmp(argv[1], "delete") == 0)
{ {
slack_command_workspace_delete(argc, argv); slack_command_workspace_delete(argc, argv);
@ -175,12 +342,15 @@ void slack_command_init()
N_("slack control"), N_("slack control"),
N_("list" N_("list"
" || register [token]" " || register [token]"
" || connect <workspace>"
" || delete <workspace>"), " || delete <workspace>"),
N_(" list: list workspaces\n" N_(" list: list workspaces\n"
"register: add a slack workspace\n" "register: add a slack workspace\n"
" connect: connect to a slack workspace\n"
" delete: delete a slack workspace\n"), " delete: delete a slack workspace\n"),
"list" "list"
" || register %(slack_token)" " || register %(slack_token)"
" || connect %(slack_workspace)"
" || delete %(slack_workspace)", " || delete %(slack_workspace)",
&slack_command_slack, NULL, NULL); &slack_command_slack, NULL, NULL);
} }

@ -17,17 +17,27 @@ int slack_config_workspace_check_value_cb(const void *pointer, void *data,
struct t_config_option *option, struct t_config_option *option,
const char *value) const char *value)
{ {
(void) pointer;
(void) data;
(void) option;
(void) value;
return 1; return 1;
} }
void slack_config_workspace_change_cb(const void *pointer, void *data, void slack_config_workspace_change_cb(const void *pointer, void *data,
struct t_config_option *option) struct t_config_option *option)
{ {
(void) pointer;
(void) data;
(void) option;
} }
void slack_config_workspace_default_change_cb(const void *pointer, void *data, void slack_config_workspace_default_change_cb(const void *pointer, void *data,
struct t_config_option *option) struct t_config_option *option)
{ {
(void) pointer;
(void) data;
(void) option;
} }
struct t_config_option * struct t_config_option *
@ -125,7 +135,7 @@ int slack_config_workspace_read_cb (const void *pointer, void *data,
{ {
struct t_slack_workspace *ptr_workspace; struct t_slack_workspace *ptr_workspace;
int index_option, rc, i; int index_option, rc, i;
char *pos_option, *workspace_name; char *pos_option, *workspace_domain;
/* make C compiler happy */ /* make C compiler happy */
(void) pointer; (void) pointer;
@ -140,17 +150,17 @@ int slack_config_workspace_read_cb (const void *pointer, void *data,
pos_option = strrchr(option_name, '.'); pos_option = strrchr(option_name, '.');
if (pos_option) if (pos_option)
{ {
workspace_name = weechat_strndup(option_name, workspace_domain = weechat_strndup(option_name,
pos_option - option_name); pos_option - option_name);
pos_option++; pos_option++;
if (workspace_name) if (workspace_domain)
{ {
index_option = slack_workspace_search_option(pos_option); index_option = slack_workspace_search_option(pos_option);
if (index_option >= 0) if (index_option >= 0)
{ {
ptr_workspace = slack_workspace_search(workspace_name); ptr_workspace = slack_workspace_search(workspace_domain);
if (!ptr_workspace) if (!ptr_workspace)
ptr_workspace = slack_workspace_alloc(workspace_name); ptr_workspace = slack_workspace_alloc(workspace_domain);
if (ptr_workspace) if (ptr_workspace)
{ {
if (ptr_workspace->reloading_from_config if (ptr_workspace->reloading_from_config
@ -172,10 +182,10 @@ int slack_config_workspace_read_cb (const void *pointer, void *data,
NULL, NULL,
_("%s%s: error adding workspace \"%s\""), _("%s%s: error adding workspace \"%s\""),
weechat_prefix("error"), SLACK_PLUGIN_NAME, weechat_prefix("error"), SLACK_PLUGIN_NAME,
workspace_name); workspace_domain);
} }
} }
free(workspace_name); free(workspace_domain);
} }
} }
} }
@ -272,12 +282,16 @@ int slack_config_init()
int slack_config_read() int slack_config_read()
{ {
return 1; int rc;
rc = weechat_config_read(slack_config_file);
return rc;
} }
int slack_config_write() int slack_config_write()
{ {
return 1; return weechat_config_write(slack_config_file);
} }
void slack_config_free() void slack_config_free()

@ -0,0 +1,20 @@
#include "weechat-plugin.h"
#include "slack-input.h"
int slack_input_data(struct t_gui_buffer *buffer, const char *input_data)
{
(void) buffer;
(void) input_data;
return WEECHAT_RC_OK;
}
int slack_input_data_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *input_data)
{
(void) pointer;
(void) data;
return slack_input_data(buffer, input_data);
}

@ -0,0 +1,8 @@
#ifndef _SLACK_INPUT_H_
#define _SLACK_INPUT_H_
int slack_input_data_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *input_data);
#endif /*SLACK_INPUT_H*/

@ -19,13 +19,13 @@ static struct lws_context *context = NULL;
static struct t_hook *slack_oauth_hook_timer = NULL; static struct t_hook *slack_oauth_hook_timer = NULL;
static int json_valid(json_object *object) static inline int json_valid(json_object *object)
{ {
if (!object) if (!object)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: Error retrieving token: unexpected response from server"), _("%s%s: error retrieving token: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME); weechat_prefix("error"), SLACK_PLUGIN_NAME);
return 0; return 0;
} }
@ -54,7 +54,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
status = lws_http_client_http_response(wsi); status = lws_http_client_http_response(wsi);
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: Retrieving token... (%d)"), _("%s%s: retrieving token... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, weechat_prefix("network"), SLACK_PLUGIN_NAME,
status); status);
break; break;
@ -67,7 +67,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: Got token: %s"), _("%s%s: got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, weechat_prefix("network"), SLACK_PLUGIN_NAME,
json_string); json_string);
@ -92,7 +92,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: Retrieved token: %s"), _("%s%s: retrieved token: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, weechat_prefix("network"), SLACK_PLUGIN_NAME,
json_object_get_string(token)); json_object_get_string(token));
@ -110,7 +110,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: Failed to retrieve token: %s"), _("%s%s: failed to retrieve token: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, weechat_prefix("error"), SLACK_PLUGIN_NAME,
json_object_get_string(error)); json_object_get_string(error));
} }
@ -133,10 +133,6 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
return 0; /* don't passthru */ return 0; /* don't passthru */
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
client_wsi = NULL;
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
break;
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
client_wsi = NULL; client_wsi = NULL;
lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
@ -161,6 +157,10 @@ static const struct lws_protocols protocols[] = {
int slack_oauth_timer_cb(const void *pointer, void *data, int remaining_calls) int slack_oauth_timer_cb(const void *pointer, void *data, int remaining_calls)
{ {
(void) pointer;
(void) data;
(void) remaining_calls;
if (n >= 0 && client_wsi) if (n >= 0 && client_wsi)
{ {
n = lws_service(context, 0); n = lws_service(context, 0);
@ -183,12 +183,19 @@ void slack_oauth_request_token(char *code, void (*callback)(char *token))
struct lws_context_creation_info info; struct lws_context_creation_info info;
struct lws_client_connect_info i; struct lws_client_connect_info i;
if (client_wsi)
{
weechat_printf(
NULL,
_("%s%s: error: a registration is already in progress"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
size_t urilen = snprintf(NULL, 0, endpoint, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, code) + 1; size_t urilen = snprintf(NULL, 0, endpoint, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, code) + 1;
uri = malloc(urilen); uri = malloc(urilen);
snprintf(uri, urilen, endpoint, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, code); snprintf(uri, urilen, endpoint, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, code);
lws_set_log_level(0, NULL);
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */ info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
@ -207,7 +214,7 @@ void slack_oauth_request_token(char *code, void (*callback)(char *token))
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: Contacting slack.com:443"), _("%s%s: contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME); weechat_prefix("network"), SLACK_PLUGIN_NAME);
} }

@ -0,0 +1,342 @@
#include <stdlib.h>
#include <string.h>
#include <libwebsockets.h>
#include <json.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-teaminfo.h"
static void (*weechat_callback)(struct t_slack_teaminfo *slack_teaminfo);
static const char *const endpoint = "/api/team.info?"
"token=%s";
static char *uri;
static int n = 0;
static struct lws *client_wsi = NULL;
static struct lws_context *context = NULL;
static struct t_hook *slack_teaminfo_hook_timer = NULL;
struct t_json_chunk
{
char *data;
struct t_json_chunk *next;
};
static struct t_json_chunk *slack_teaminfo_chunks = NULL;
static struct t_slack_teaminfo slack_teaminfo;
static inline int json_valid(json_object *object)
{
if (!object)
{
weechat_printf(
NULL,
_("%s%s: Error retrieving workspace info: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return 0;
}
return 1;
}
static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
void *user, void *in, size_t len)
{
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
NULL,
_("%s%s: error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
in ? (char *)in : "(null)");
client_wsi = NULL;
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
NULL,
_("%s%s: retrieving workspace details... (%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 (slack_teaminfo_chunks)
{
for (last_chunk = slack_teaminfo_chunks; last_chunk->next;
last_chunk = last_chunk->next);
last_chunk->next = new_chunk;
}
else
{
slack_teaminfo_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, *team;
json_object *id, *name, *domain, *email_domain;
struct t_json_chunk *chunk_ptr;
chunk_count = 0;
if (slack_teaminfo_chunks)
{
chunk_count++;
for (chunk_ptr = slack_teaminfo_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 = slack_teaminfo_chunks;
for (i = 0; i < chunk_count; i++)
{
strncat(json_string, chunk_ptr->data, 1024);
chunk_ptr = chunk_ptr->next;
free(slack_teaminfo_chunks->data);
free(slack_teaminfo_chunks);
slack_teaminfo_chunks = chunk_ptr;
}
weechat_printf(
NULL,
_("%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))
{
json_object_put(response);
free(json_string);
return 0;
}
if(json_object_get_boolean(ok))
{
team = json_object_object_get(response, "team");
if (!json_valid(team))
{
json_object_put(response);
free(json_string);
return 0;
}
id = json_object_object_get(team, "id");
if (!json_valid(id))
{
json_object_put(response);
free(json_string);
return 0;
}
name = json_object_object_get(team, "name");
if (!json_valid(name))
{
json_object_put(response);
free(json_string);
return 0;
}
domain = json_object_object_get(team, "domain");
if (!json_valid(domain))
{
json_object_put(response);
free(json_string);
return 0;
}
email_domain = json_object_object_get(team, "email_domain");
if (!json_valid(email_domain))
{
json_object_put(response);
free(json_string);
return 0;
}
weechat_printf(
NULL,
_("%s%s: retrieved workspace details for %s@%s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME,
json_object_get_string(name), json_object_get_string(domain));
slack_teaminfo.id = json_object_get_string(id);
slack_teaminfo.name = json_object_get_string(name);
slack_teaminfo.domain = json_object_get_string(domain);
slack_teaminfo.email_domain = json_object_get_string(email_domain);
weechat_callback(&slack_teaminfo);
}
else
{
error = json_object_object_get(response, "error");
if (!json_valid(error))
{
json_object_put(response);
free(json_string);
return 0;
}
weechat_printf(
NULL,
_("%s%s: failed to retrieve workspace details: %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:
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 }
};
int slack_teaminfo_timer_cb(const void *pointer, void *data, int remaining_calls)
{
(void) pointer;
(void) data;
(void) remaining_calls;
if (n >= 0 && client_wsi)
{
n = lws_service(context, 0);
}
else if (context)
{
lws_context_destroy(context);
context = NULL;
free(uri);
if (slack_teaminfo_hook_timer)
weechat_unhook(slack_teaminfo_hook_timer);
}
return WEECHAT_RC_OK;
}
void slack_teaminfo_fetch(char *token, void (*callback)(struct t_slack_teaminfo *slack_teaminfo))
{
struct lws_context_creation_info info;
struct lws_client_connect_info i;
if (client_wsi)
{
weechat_printf(
NULL,
_("%s%s: error: a registration is already in progress"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
slack_teaminfo.token = strdup(token);
size_t urilen = snprintf(NULL, 0, endpoint, token) + 1;
uri = malloc(urilen);
snprintf(uri, urilen, endpoint, token);
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
context = lws_create_context(&info);
if (!context)
{
weechat_printf(
NULL,
_("%s%s: error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
else
{
weechat_printf(
NULL,
_("%s%s: contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME);
}
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
i.context = context;
i.ssl_connection = LCCSCF_USE_SSL;
i.port = 443;
i.address = "slack.com";
i.path = uri;
i.host = i.address;
i.origin = i.address;
i.method = "GET";
i.protocol = protocols[0].name;
i.pwsi = &client_wsi;
lws_client_connect_via_info(&i);
slack_teaminfo_hook_timer = weechat_hook_timer(1 * 1000, 0, 0,
&slack_teaminfo_timer_cb,
NULL, NULL);
weechat_callback = callback;
}
void free_teaminfo(struct t_slack_teaminfo *teaminfo)
{
free(teaminfo->token);
}

@ -0,0 +1,16 @@
#ifndef _SLACK_TEAMINFO_H_
#define _SLACK_TEAMINFO_H_
struct t_slack_teaminfo
{
const char *id;
const char *name;
const char *domain;
const char *email_domain;
char *token;
};
extern void slack_teaminfo_fetch(char *token, void (*callback)(struct t_slack_teaminfo *slack_teaminfo));
extern void free_teaminfo(struct t_slack_teaminfo *teaminfo);
#endif /*SLACK_TEAMINFO_H*/

@ -1,11 +1,17 @@
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <assert.h>
#include "weechat-plugin.h" #include "weechat-plugin.h"
#include "slack.h" #include "slack.h"
#include "slack-buffer.h"
#include "slack-config.h" #include "slack-config.h"
#include "slack-input.h"
#include "slack-workspace.h" #include "slack-workspace.h"
#include "slack-api.h"
struct t_slack_workspace *slack_workspaces = NULL; struct t_slack_workspace *slack_workspaces = NULL;
struct t_slack_workspace *last_slack_workspace = NULL; struct t_slack_workspace *last_slack_workspace = NULL;
@ -14,17 +20,264 @@ char *slack_workspace_options[SLACK_WORKSPACE_NUM_OPTIONS][2] =
{ { "token", "" }, { { "token", "" },
}; };
struct t_slack_workspace *slack_workspace_search(const char *workspace_name) static const char *const endpoint = "/api/rtm.connect?"
"token=%s&batch_presence_aware=true&presence_sub=false";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: Error requesting websocket: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
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_workspace *workspace = (struct t_slack_workspace *)user;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
workspace->buffer,
_("%s%s: error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
in ? (char *)in : "(null)");
workspace->client_wsi = NULL;
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
workspace->buffer,
_("%s%s: requesting a websocket... (%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 (workspace->json_chunks)
{
for (last_chunk = workspace->json_chunks; last_chunk->next;
last_chunk = last_chunk->next);
last_chunk->next = new_chunk;
}
else
{
workspace->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, *self, *team, *url;
json_object *id, *name, *domain;
struct t_json_chunk *chunk_ptr;
chunk_count = 0;
if (workspace->json_chunks)
{
chunk_count++;
for (chunk_ptr = workspace->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 = workspace->json_chunks;
for (i = 0; i < chunk_count; i++)
{
strncat(json_string, chunk_ptr->data, 1024);
chunk_ptr = chunk_ptr->next;
free(workspace->json_chunks->data);
free(workspace->json_chunks);
workspace->json_chunks = chunk_ptr;
}
weechat_printf(
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, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
if(json_object_get_boolean(ok))
{
self = json_object_object_get(response, "self");
if (!json_valid(self, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
else
{
id = json_object_object_get(self, "id");
if (!json_valid(id, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
workspace->user = strdup(json_object_get_string(id));
name = json_object_object_get(self, "name");
if (!json_valid(name, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
workspace->nick = strdup(json_object_get_string(name));
}
team = json_object_object_get(response, "team");
if (!json_valid(team, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
else
{
domain = json_object_object_get(team, "domain");
if (!json_valid(domain, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
id = json_object_object_get(team, "id");
if (!json_valid(id, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
workspace->id = strdup(json_object_get_string(id));
name = json_object_object_get(team, "name");
if (!json_valid(name, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
workspace->name = strdup(json_object_get_string(name));
}
url = json_object_object_get(response, "url");
if (!json_valid(url, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
workspace->ws_url = strdup(json_object_get_string(url));
}
else
{
error = json_object_object_get(response, "error");
if (!json_valid(error, workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
weechat_printf(
workspace->buffer,
_("%s%s: failed to request websocket: %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:
workspace->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_workspace *slack_workspace_search(const char *workspace_domain)
{ {
struct t_slack_workspace *ptr_workspace; struct t_slack_workspace *ptr_workspace;
if (!workspace_name) if (!workspace_domain)
return NULL; return NULL;
for (ptr_workspace = slack_workspaces; ptr_workspace; for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace) ptr_workspace = ptr_workspace->next_workspace)
{ {
if (strcmp(ptr_workspace->name, workspace_name) == 0) if (strcmp(ptr_workspace->domain, workspace_domain) == 0)
return ptr_workspace; return ptr_workspace;
} }
@ -32,17 +285,17 @@ struct t_slack_workspace *slack_workspace_search(const char *workspace_name)
return NULL; return NULL;
} }
struct t_slack_workspace *slack_workspace_casesearch (const char *workspace_name) struct t_slack_workspace *slack_workspace_casesearch (const char *workspace_domain)
{ {
struct t_slack_workspace *ptr_workspace; struct t_slack_workspace *ptr_workspace;
if (!workspace_name) if (!workspace_domain)
return NULL; return NULL;
for (ptr_workspace = slack_workspaces; ptr_workspace; for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace) ptr_workspace = ptr_workspace->next_workspace)
{ {
if (weechat_strcasecmp (ptr_workspace->name, workspace_name) == 0) if (weechat_strcasecmp (ptr_workspace->domain, workspace_domain) == 0)
return ptr_workspace; return ptr_workspace;
} }
@ -67,13 +320,13 @@ int slack_workspace_search_option(const char *option_name)
return -1; return -1;
} }
struct t_slack_workspace *slack_workspace_alloc(const char *name) struct t_slack_workspace *slack_workspace_alloc(const char *domain)
{ {
struct t_slack_workspace *new_workspace; struct t_slack_workspace *new_workspace;
int i, length; int i, length;
char *option_name; char *option_name;
if (slack_workspace_casesearch(name)) if (slack_workspace_casesearch(domain))
return NULL; return NULL;
/* alloc memory for new workspace */ /* alloc memory for new workspace */
@ -95,19 +348,36 @@ struct t_slack_workspace *slack_workspace_alloc(const char *name)
slack_workspaces = new_workspace; slack_workspaces = new_workspace;
last_slack_workspace = new_workspace; last_slack_workspace = new_workspace;
/* set properties */
new_workspace->id = NULL;
new_workspace->name = NULL;
/* set name */ /* set name */
new_workspace->name = strdup(name); new_workspace->domain = strdup(domain);
/* internal vars */ /* internal vars */
new_workspace->reloading_from_config = 0; new_workspace->reloading_from_config = 0;
new_workspace->reloaded_from_config = 0; new_workspace->reloaded_from_config = 0;
new_workspace->is_connected = 0; new_workspace->is_connected = 0;
new_workspace->disconnected = 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->user = NULL;
new_workspace->nick = NULL;
new_workspace->buffer = NULL;
new_workspace->buffer_as_string = NULL;
/* create options with null value */ /* create options with null value */
for (i = 0; i < SLACK_WORKSPACE_NUM_OPTIONS; i++) for (i = 0; i < SLACK_WORKSPACE_NUM_OPTIONS; i++)
{ {
length = strlen(new_workspace->name) + 1 + length = strlen(new_workspace->domain) + 1 +
strlen(slack_workspace_options[i][0]) + strlen(slack_workspace_options[i][0]) +
512 + /* inherited option name(slack.workspace_default.xxx) */ 512 + /* inherited option name(slack.workspace_default.xxx) */
1; 1;
@ -115,7 +385,7 @@ struct t_slack_workspace *slack_workspace_alloc(const char *name)
if (option_name) if (option_name)
{ {
snprintf(option_name, length, "%s.%s << slack.workspace_default.%s", snprintf(option_name, length, "%s.%s << slack.workspace_default.%s",
new_workspace->name, new_workspace->domain,
slack_workspace_options[i][0], slack_workspace_options[i][0],
slack_workspace_options[i][0]); slack_workspace_options[i][0]);
new_workspace->options[i] = slack_config_workspace_new_option( new_workspace->options[i] = slack_config_workspace_new_option(
@ -140,3 +410,378 @@ struct t_slack_workspace *slack_workspace_alloc(const char *name)
return new_workspace; return new_workspace;
} }
void slack_workspace_free_data(struct t_slack_workspace *workspace)
{
int i;
if (!workspace)
return;
/* free linked lists */
/*
for (i = 0; i < IRC_SERVER_NUM_OUTQUEUES_PRIO; i++)
{
slack_workspace_outqueue_free_all(workspace, i);
}
slack_redirect_free_all(workspace);
slack_notify_free_all(workspace);
slack_channel_free_all(workspace);
*/
/* free hashtables */
/*
weechat_hashtable_free(workspace->join_manual);
weechat_hashtable_free(workspace->join_channel_key);
weechat_hashtable_free(workspace->join_noswitch);
*/
/* free workspace data */
for (i = 0; i < SLACK_WORKSPACE_NUM_OPTIONS; i++)
{
if (workspace->options[i])
weechat_config_option_free(workspace->options[i]);
}
if (workspace->id)
free(workspace->id);
if (workspace->name)
free(workspace->name);
if (workspace->domain)
free(workspace->domain);
if (workspace->uri)
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);
while (workspace->json_chunks)
{
struct t_json_chunk *chunk_ptr = workspace->json_chunks->next;
free(workspace->json_chunks->data);
free(workspace->json_chunks);
workspace->json_chunks = chunk_ptr;
}
if (workspace->user)
free(workspace->user);
if (workspace->nick)
free(workspace->nick);
if (workspace->buffer_as_string)
free(workspace->buffer_as_string);
}
void slack_workspace_free(struct t_slack_workspace *workspace)
{
struct t_slack_workspace *new_slack_workspaces;
if (!workspace)
return;
/*
* close workspace buffer (and all channels/privates)
* (only if we are not in a /upgrade, because during upgrade we want to
* keep connections and closing workspace buffer would disconnect from workspace)
*/
if (workspace->buffer)
weechat_buffer_close(workspace->buffer);
/* remove workspace from queue */
if (last_slack_workspace == workspace)
last_slack_workspace = workspace->prev_workspace;
if (workspace->prev_workspace)
{
(workspace->prev_workspace)->next_workspace = workspace->next_workspace;
new_slack_workspaces = slack_workspaces;
}
else
new_slack_workspaces = workspace->next_workspace;
if (workspace->next_workspace)
(workspace->next_workspace)->prev_workspace = workspace->prev_workspace;
slack_workspace_free_data(workspace);
free(workspace);
slack_workspaces = new_slack_workspaces;
}
void slack_workspace_free_all()
{
/* for each workspace in memory, remove it */
while (slack_workspaces)
{
slack_workspace_free(slack_workspaces);
}
}
void slack_workspace_disconnect(struct t_slack_workspace *workspace,
int switch_address, int reconnect)
{
(void) switch_address;
(void) reconnect;
struct t_slack_channel *ptr_channel;
(void) ptr_channel;
if (workspace->is_connected)
{
/*
* remove all nicks and write disconnection message on each
* channel/private buffer
*/
/*
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)
{
weechat_printf(
workspace->buffer,
_("%s%s: disconnected from workspace"),
weechat_prefix ("network"), SLACK_PLUGIN_NAME);
}
workspace->current_retry = 0;
if (switch_address)
slack_workspace_switch_address(workspace, 0);
else
slack_workspace_set_index_current_address(workspace, 0);
if (workspace->nick_modes)
{
free (workspace->nick_modes);
workspace->nick_modes = NULL;
weechat_bar_item_update ("input_prompt");
weechat_bar_item_update ("slack_nick_modes");
}
workspace->cap_away_notify = 0;
workspace->cap_account_notify = 0;
workspace->cap_extended_join = 0;
workspace->is_away = 0;
workspace->away_time = 0;
workspace->lag = 0;
workspace->lag_displayed = -1;
workspace->lag_check_time.tv_sec = 0;
workspace->lag_check_time.tv_usec = 0;
workspace->lag_next_check = time (NULL) +
weechat_config_integer (slack_config_network_lag_check);
workspace->lag_last_refresh = 0;
slack_workspace_set_lag (workspace);
workspace->monitor = 0;
workspace->monitor_time = 0;
if (reconnect
&& IRC_SERVER_OPTION_BOOLEAN(workspace, IRC_SERVER_OPTION_AUTORECONNECT))
slack_workspace_reconnect_schedule(workspace);
else
{
workspace->reconnect_delay = 0;
workspace->reconnect_start = 0;
}
*/
/* discard current nick if no reconnection asked */
/*
if (!reconnect && workspace->nick)
slack_workspace_set_nick(workspace, NULL);
slack_workspace_set_buffer_title(workspace);
workspace->disconnected = 1;
*/
/* send signal "slack_workspace_disconnected" with workspace name */
/*
(void) weechat_hook_signal_send("slack_workspace_disconnected",
WEECHAT_HOOK_SIGNAL_STRING, workspace->name);
*/
}
void slack_workspace_disconnect_all()
{
struct t_slack_workspace *ptr_workspace;
for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace)
{
slack_workspace_disconnect(ptr_workspace, 0, 0);
}
}
struct t_gui_buffer *slack_workspace_create_buffer(struct t_slack_workspace *workspace)
{
char buffer_name[256], charset_modifier[256];
snprintf(buffer_name, sizeof(buffer_name),
"slack.%s", workspace->domain);
workspace->buffer = weechat_buffer_new(buffer_name,
&slack_input_data_cb, NULL, NULL,
&slack_buffer_close_cb, NULL, NULL);
if (!workspace->buffer)
return NULL;
if (!weechat_buffer_get_integer(workspace->buffer, "short_name_is_set"))
weechat_buffer_set(workspace->buffer, "short_name", workspace->domain);
weechat_buffer_set(workspace->buffer, "localvar_set_type", "server");
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);
weechat_buffer_set(workspace->buffer, "localvar_set_charset_modifier",
charset_modifier);
weechat_buffer_set(workspace->buffer, "title",
(workspace->name) ? workspace->name : "");
return workspace->buffer;
}
void slack_workspace_close_connection(struct t_slack_workspace *workspace)
{
workspace->is_connected = 0;
workspace->client_wsi = NULL;
workspace->context = NULL;
}
void slack_workspace_websocket_create(struct t_slack_workspace *workspace)
{
struct lws_context_creation_info info;
struct lws_client_connect_info i;
const char *token;
if (workspace->client_wsi)
{
weechat_printf(
workspace->buffer,
_("%s%s: error: a websocket already exists"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
token = weechat_config_string(workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]);
size_t urilen = snprintf(NULL, 0, endpoint, token) + 1;
workspace->uri = malloc(urilen);
snprintf(workspace->uri, urilen, endpoint, token);
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
workspace->context = lws_create_context(&info);
if (!workspace->context)
{
weechat_printf(
workspace->buffer,
_("%s%s: error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME);
}
memset(&i, 0, sizeof i); /* otherwise uninitialized garbage */
i.context = workspace->context;
i.ssl_connection = LCCSCF_USE_SSL;
i.port = 443;
i.address = "slack.com";
i.path = workspace->uri;
i.host = i.address;
i.origin = i.address;
i.method = "GET";
i.protocol = protocols[0].name;
i.pwsi = &workspace->client_wsi;
i.userdata = workspace;
lws_client_connect_via_info(&i);
workspace->is_connected = 1;
}
int slack_workspace_connect(struct t_slack_workspace *workspace)
{
workspace->disconnected = 0;
if (!workspace->buffer)
{
if (!slack_workspace_create_buffer(workspace))
return 0;
weechat_buffer_set(workspace->buffer, "display", "auto");
}
slack_workspace_close_connection(workspace);
slack_workspace_websocket_create(workspace);
return 1;
}
int slack_workspace_timer_cb(const void *pointer, void *data, int remaining_calls)
{
struct t_slack_workspace *ptr_workspace;
/* make C compiler happy */
(void) pointer;
(void) data;
(void) remaining_calls;
for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace)
{
if (!ptr_workspace->is_connected)
continue;
if (ptr_workspace->client_wsi)
{
lws_service(ptr_workspace->context, 0);
}
else if (ptr_workspace->context)
{
lws_context_destroy(ptr_workspace->context);
ptr_workspace->context = NULL;
if (ptr_workspace->uri)
{
free(ptr_workspace->uri);
ptr_workspace->uri = NULL;
}
if (ptr_workspace->ws_url)
{
slack_api_connect(ptr_workspace);
free(ptr_workspace->ws_url);
ptr_workspace->ws_url = NULL;
}
}
}
return WEECHAT_RC_OK;
}

@ -10,24 +10,54 @@ enum t_slack_workspace_option
SLACK_WORKSPACE_NUM_OPTIONS, SLACK_WORKSPACE_NUM_OPTIONS,
}; };
struct t_json_chunk
{
char *data;
struct t_json_chunk *next;
};
struct t_slack_workspace struct t_slack_workspace
{ {
char *id;
char *name; char *name;
char *domain;
struct t_config_option *options[SLACK_WORKSPACE_NUM_OPTIONS]; struct t_config_option *options[SLACK_WORKSPACE_NUM_OPTIONS];
int reloading_from_config; int reloading_from_config;
int reloaded_from_config; int reloaded_from_config;
int is_connected; int is_connected;
int disconnected;
char *uri;
char *ws_url;
struct lws *client_wsi;
struct lws_context *context;
struct t_json_chunk *json_chunks;
char *user;
char *nick;
struct t_gui_buffer *buffer;
char *buffer_as_string;
struct t_slack_workspace *prev_workspace; struct t_slack_workspace *prev_workspace;
struct t_slack_workspace *next_workspace; struct t_slack_workspace *next_workspace;
}; };
extern char *slack_workspace_options[][2]; extern char *slack_workspace_options[][2];
struct t_slack_workspace *slack_workspace_search(const char *workspace_name); struct t_slack_workspace *slack_workspace_search(const char *workspace_domain);
struct t_slack_workspace *slack_workspace_casesearch (const char *workspace_domain);
int slack_workspace_search_option(const char *option_name); int slack_workspace_search_option(const char *option_name);
struct t_slack_workspace *slack_workspace_alloc(const char *name); struct t_slack_workspace *slack_workspace_alloc(const char *domain);
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);
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);
#endif /*SLACK_WORKSPACE_H*/ #endif /*SLACK_WORKSPACE_H*/

@ -1,11 +1,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <libwebsockets.h>
#include "weechat-plugin.h" #include "weechat-plugin.h"
#include "slack.h" #include "slack.h"
#include "slack-config.h" #include "slack-config.h"
#include "slack-command.h" #include "slack-command.h"
#include "slack-workspace.h"
WEECHAT_PLUGIN_NAME(SLACK_PLUGIN_NAME); WEECHAT_PLUGIN_NAME(SLACK_PLUGIN_NAME);
@ -17,6 +19,20 @@ WEECHAT_PLUGIN_PRIORITY(6000);
struct t_weechat_plugin *weechat_slack_plugin = NULL; struct t_weechat_plugin *weechat_slack_plugin = NULL;
struct t_hook *slack_hook_timer = NULL;
void slack_lwsl_emit_weechat(int level, const char *line)
{
char buf[50];
lwsl_timestamp(level, buf, sizeof(buf));
weechat_printf(
NULL,
_("%s%s: %s%s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
buf, line);
}
int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
{ {
(void) argc; (void) argc;
@ -24,6 +40,11 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
weechat_plugin = plugin; weechat_plugin = plugin;
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG
| LLL_PARSER | LLL_HEADER | LLL_EXT | LLL_CLIENT
| LLL_LATENCY | LLL_USER | LLL_COUNT,
slack_lwsl_emit_weechat);
if (!slack_config_init()) if (!slack_config_init())
return WEECHAT_RC_ERROR; return WEECHAT_RC_ERROR;
@ -31,6 +52,10 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
slack_command_init(); slack_command_init();
slack_hook_timer = weechat_hook_timer(1 * 1000, 0, 0,
&slack_workspace_timer_cb,
NULL, NULL);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
@ -39,5 +64,14 @@ int weechat_plugin_end(struct t_weechat_plugin *plugin)
/* make C compiler happy */ /* make C compiler happy */
(void) plugin; (void) plugin;
if (slack_hook_timer)
weechat_unhook(slack_hook_timer);
slack_config_write();
slack_workspace_disconnect_all();
slack_workspace_free_all();
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }

Loading…
Cancel
Save