v1
Tony Olagbaiye 3 years ago
parent ae0ada316e
commit a97d77f332
No known key found for this signature in database
GPG Key ID: 9E2FF3BDEBDFC910

@ -13,10 +13,10 @@ PREFIX ?= /usr/local
LIBDIR ?= $(PREFIX)/lib
INSTALL ?= /usr/bin/install
SRCS=xmpp.c \
xmpp-command.c \
xmpp-config.c \
xmpp-connection.c \
SRCS=plugin.c \
command.c \
config.c \
connection.c \
DEPS=json-c/libjson-c.a
OLDSRCS=slack.c \

@ -1,155 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../../weechat-plugin.h"
#include "../../slack.h"
#include "../../slack-workspace.h"
#include "../../slack-message.h"
#include "../../slack-api.h"
#include "../../slack-channel.h"
#include "../../slack-user.h"
#include "../slack-api-message.h"
#include "slack-api-message-bot-message.h"
static const char *subtype = "bot_message";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %smessage.%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), subtype, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_bot_message_handle(struct t_slack_workspace *workspace,
const char *channel, const char *bot_id,
const char *username, const char *text,
const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_bot_search(workspace, bot_id);
if (!ptr_user)
return 1; /* silently ignore if bot user hasn't been loaded yet */
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message,slack_bot_message",
_("%s%s"),
slack_user_as_prefix(workspace, ptr_user, username),
message);
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
return 1;
}
int slack_api_message_slackbot_message_handle(struct t_slack_workspace *workspace,
const char *channel, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; /* silently ignore if slackbot user hasn't been loaded yet */
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message,slack_slackbot_message",
_("%s%s"),
slack_user_as_prefix(workspace, ptr_user, user),
message);
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
return 1;
}
int slack_api_message_bot_message(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *channel, *bot_id, *username, *user, *text, *ts;
channel = json_object_object_get(message, "channel");
if (!json_valid(channel, workspace))
return 0;
username = json_object_object_get(message, "username");
if (!json_valid(username, workspace))
return 0;
text = json_object_object_get(message, "text");
if (!json_valid(text, workspace))
return 0;
ts = json_object_object_get(message, "ts");
if (!json_valid(ts, workspace))
return 0;
if (strcmp("slackbot", json_object_get_string(username)) == 0)
{
user = json_object_object_get(message, "user");
if (!json_valid(user, workspace))
return 0;
return slack_api_message_slackbot_message_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user),
json_object_get_string(text),
json_object_get_string(ts));
}
else
{
bot_id = json_object_object_get(message, "bot_id");
if (!json_valid(bot_id, workspace))
return 0;
return slack_api_message_bot_message_handle(workspace,
json_object_get_string(channel),
json_object_get_string(bot_id),
json_object_get_string(username),
json_object_get_string(text),
json_object_get_string(ts));
}
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_BOT_MESSAGE_H_
#define _SLACK_API_MESSAGE_BOT_MESSAGE_H_
int slack_api_message_bot_message(
struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_MESSAGE_BOT_MESSAGE_H*/

@ -1,102 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../../weechat-plugin.h"
#include "../../slack.h"
#include "../../slack-workspace.h"
#include "../../slack-message.h"
#include "../../slack-api.h"
#include "../../slack-channel.h"
#include "../../slack-user.h"
#include "../slack-api-message.h"
#include "slack-api-message-me-message.h"
static const char *subtype = "me_message";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %smessage.%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), subtype, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_me_message_handle(struct t_slack_workspace *workspace,
const char *channel, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; /* silently ignore if user hasn't been loaded yet */
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message,slack_me_message",
_("%s%s%s%s%s%s"),
weechat_prefix("action"),
slack_user_get_colour(ptr_user),
ptr_user->profile.display_name,
weechat_color("reset"),
message[0] ? " " : "",
message);
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
return 1;
}
int slack_api_message_me_message(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *channel, *user, *text, *ts;
channel = json_object_object_get(message, "channel");
if (!json_valid(channel, workspace))
return 0;
user = json_object_object_get(message, "user");
if (!json_valid(user, workspace))
return 0;
text = json_object_object_get(message, "text");
if (!json_valid(text, workspace))
return 0;
ts = json_object_object_get(message, "ts");
if (!json_valid(ts, workspace))
return 0;
return slack_api_message_me_message_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user),
json_object_get_string(text),
json_object_get_string(ts));
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_ME_MESSAGE_H_
#define _SLACK_API_MESSAGE_ME_MESSAGE_H_
int slack_api_message_me_message(
struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_MESSAGE_ME_MESSAGE_H*/

@ -1,104 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../../weechat-plugin.h"
#include "../../slack.h"
#include "../../slack-workspace.h"
#include "../../slack-message.h"
#include "../../slack-api.h"
#include "../../slack-channel.h"
#include "../../slack-user.h"
#include "../slack-api-message.h"
#include "slack-api-message-message-changed.h"
static const char *subtype = "message_changed";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %smessage.%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), subtype, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_message_changed_handle(struct t_slack_workspace *workspace,
json_object *root, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
/*
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; // silently ignore if channel hasn't been loaded yet
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; // silently ignore if user hasn't been loaded yet
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message,slack_thread_broadcast",
_("%s%s"),
slack_user_as_prefix(workspace, ptr_user, NULL),
message);
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
*/
return 1;
}
int slack_api_message_message_changed(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *channel, *oldmsg, *user, *text, *ts;
channel = json_object_object_get(message, "channel");
if (!json_valid(channel, workspace))
return 0;
oldmsg = json_object_object_get(message, "message");
if (!json_valid(oldmsg, workspace))
return 0;
user = json_object_object_get(oldmsg, "user");
if (!json_valid(user, workspace))
return 0;
text = json_object_object_get(message, "text");
if (!json_valid(text, workspace))
return 0;
ts = json_object_object_get(message, "ts");
if (!json_valid(ts, workspace))
return 0;
return slack_api_message_message_changed_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user),
json_object_get_string(text),
json_object_get_string(ts));
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_MESSAGE_CHANGED_H_
#define _SLACK_API_MESSAGE_MESSAGE_CHANGED_H_
int slack_api_message_message_changed(
struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_MESSAGE_MESSAGE_CHANGED_H*/

@ -1,98 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../../weechat-plugin.h"
#include "../../slack.h"
#include "../../slack-workspace.h"
#include "../../slack-message.h"
#include "../../slack-api.h"
#include "../../slack-channel.h"
#include "../../slack-user.h"
#include "../slack-api-message.h"
#include "slack-api-message-slackbot-response.h"
static const char *subtype = "slackbot_response";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %smessage.%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), subtype, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_slackbot_response_handle(struct t_slack_workspace *workspace,
const char *channel, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; /* silently ignore if slackbot user hasn't been loaded yet */
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message,slack_slackbot_response",
_("%s%s"),
slack_user_as_prefix(workspace, ptr_user, "slackbot"),
message);
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
return 1;
}
int slack_api_message_slackbot_response(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *channel, *user, *text, *ts;
channel = json_object_object_get(message, "channel");
if (!json_valid(channel, workspace))
return 0;
user = json_object_object_get(message, "user");
if (!json_valid(user, workspace))
return 0;
text = json_object_object_get(message, "text");
if (!json_valid(text, workspace))
return 0;
ts = json_object_object_get(message, "ts");
if (!json_valid(ts, workspace))
return 0;
return slack_api_message_slackbot_response_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user),
json_object_get_string(text),
json_object_get_string(ts));
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_SLACKBOT_RESPONSE_H_
#define _SLACK_API_MESSAGE_SLACKBOT_RESPONSE_H_
int slack_api_message_slackbot_response(
struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_MESSAGE_SLACKBOT_RESPONSE_H*/

@ -1,99 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../../weechat-plugin.h"
#include "../../slack.h"
#include "../../slack-workspace.h"
#include "../../slack-message.h"
#include "../../slack-api.h"
#include "../../slack-channel.h"
#include "../../slack-user.h"
#include "../slack-api-message.h"
#include "slack-api-message-thread-broadcast.h"
static const char *subtype = "thread_broadcast";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %smessage.%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), subtype, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_thread_broadcast_handle(struct t_slack_workspace *workspace,
json_object *root, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
/*
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; // silently ignore if channel hasn't been loaded yet
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; // silently ignore if user hasn't been loaded yet
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message,slack_thread_broadcast",
_("%s%s"),
slack_user_as_prefix(workspace, ptr_user, NULL),
message);
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
*/
return 1;
}
int slack_api_message_thread_broadcast(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *root, *user, *text, *ts;
root = json_object_object_get(message, "root");
if (!json_valid(root, workspace))
return 0;
user = json_object_object_get(message, "user");
if (!json_valid(user, workspace))
return 0;
text = json_object_object_get(message, "text");
if (!json_valid(text, workspace))
return 0;
ts = json_object_object_get(message, "ts");
if (!json_valid(ts, workspace))
return 0;
return slack_api_message_thread_broadcast_handle(workspace,
root, json_object_get_string(user),
json_object_get_string(text),
json_object_get_string(ts));
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_THREAD_BROADCAST_H_
#define _SLACK_API_MESSAGE_THREAD_BROADCAST_H_
int slack_api_message_thread_broadcast(
struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_MESSAGE_THREAD_BROADCAST_H*/

@ -1,50 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../../weechat-plugin.h"
#include "../../slack.h"
#include "../../slack-workspace.h"
#include "../../slack-api.h"
#include "../../slack-channel.h"
#include "../../slack-user.h"
#include "../slack-api-message.h"
#include "slack-api-message-unimplemented.h"
static const char *subtype = "unimplemented";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %smessage.%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), subtype, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_unimplemented(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *subtype = json_object_object_get(message, "subtype");
if (!json_valid(subtype, workspace))
return 0;
weechat_printf(
workspace->buffer,
_("%s%s: got unhandled message of type: message.%s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
json_object_get_string(subtype));
return 1;
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_UNIMPLEMENTED_H_
#define _SLACK_API_MESSAGE_UNIMPLEMENTED_H_
int slack_api_message_unimplemented(
struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_MESSAGE_UNIMPLEMENTED_H*/

@ -1,63 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#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));
}

@ -1,11 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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*/

@ -1,54 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#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"
#include "../request/slack-request-emoji-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);
request = slack_request_emoji_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);
}

@ -1,11 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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*/

@ -1,240 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-api.h"
#include "../slack-channel.h"
#include "../slack-user.h"
#include "../slack-message.h"
#include "slack-api-message.h"
#include "message/slack-api-message-unimplemented.h"
#include "message/slack-api-message-bot-message.h"
#include "message/slack-api-message-me-message.h"
#include "message/slack-api-message-slackbot-response.h"
static const char *type = "message";
struct stringcase
{
const char *string;
int (*func)(struct t_slack_workspace *workspace,
json_object *message);
};
static struct stringcase cases[] =
{ { "bot_message", &slack_api_message_bot_message }
, { "channel_archive", &slack_api_message_unimplemented }
, { "channel_join", &slack_api_message_unimplemented }
, { "channel_leave", &slack_api_message_unimplemented }
, { "channel_name", &slack_api_message_unimplemented }
, { "channel_purpose", &slack_api_message_unimplemented }
, { "channel_topic", &slack_api_message_unimplemented }
, { "channel_unarchive", &slack_api_message_unimplemented }
, { "file_comment", &slack_api_message_unimplemented }
, { "file_mention", &slack_api_message_unimplemented }
, { "file_share", &slack_api_message_unimplemented }
, { "group_archive", &slack_api_message_unimplemented }
, { "group_join", &slack_api_message_unimplemented }
, { "group_leave", &slack_api_message_unimplemented }
, { "group_name", &slack_api_message_unimplemented }
, { "group_purpose", &slack_api_message_unimplemented }
, { "group_topic", &slack_api_message_unimplemented }
, { "group_unarchive", &slack_api_message_unimplemented }
, { "me_message", &slack_api_message_me_message }
, { "message_changed", &slack_api_message_unimplemented }
, { "message_deleted", &slack_api_message_unimplemented }
, { "message_replied", &slack_api_message_unimplemented }
, { "pinned_item", &slack_api_message_unimplemented }
, { "reply_broadcast", &slack_api_message_unimplemented }
, { "slackbot_response", &slack_api_message_slackbot_response }
, { "thread_broadcast", &slack_api_message_unimplemented }
, { "unpinned_item", &slack_api_message_unimplemented }
};
static int stringcase_cmp(const void *p1, const void *p2)
{
return strcasecmp(((struct stringcase*)p1)->string, ((struct stringcase*)p2)->string);
}
void slack_api_message_init()
{
size_t case_count = sizeof(cases) / sizeof(cases[0]);
qsort(cases, case_count, sizeof(struct stringcase), stringcase_cmp);
}
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error handling websocket %s%s%s message: "
"unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
weechat_color("chat_value"), type, weechat_color("reset"));
return 0;
}
return 1;
}
int slack_api_message_message_handle(struct t_slack_workspace *workspace,
const char *channel, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; /* silently ignore if user hasn't been loaded yet */
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message",
_("%s%s"),
slack_user_as_prefix(workspace, ptr_user, NULL),
message);
slack_channel_member_speaking_add(ptr_channel, ptr_user->profile.display_name,
weechat_string_has_highlight(
message,
ptr_user->profile.display_name));
free(message);
ptr_typing = slack_channel_typing_search(ptr_channel,
ptr_user->profile.display_name);
if (ptr_typing)
{
slack_channel_typing_free(ptr_channel, ptr_typing);
slack_channel_typing_cb(ptr_channel, NULL, 0);
}
return 1;
}
int slack_api_message_attachment_handle(struct t_slack_workspace *workspace,
const char *channel, const char *user,
const char *text, const char *ts)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; /* silently ignore if user hasn't been loaded yet */
char *message = slack_message_decode(workspace, text);
weechat_printf_date_tags(
ptr_channel->buffer,
(time_t)atof(ts),
"slack_message",
_("%s%s"),
"++\t",
message);
free(message);
return 1;
}
int slack_api_message_route_message(struct t_slack_workspace *workspace,
const char *subtype,
json_object *message)
{
struct stringcase key;
key.string = subtype;
size_t case_count = sizeof(cases) / sizeof(cases[0]);
void *entry_ptr = bsearch(&key, cases, case_count,
sizeof(struct stringcase), stringcase_cmp);
if (entry_ptr)
{
struct stringcase *entry = (struct stringcase *)entry_ptr;
return (*entry->func)(workspace, message);
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: got unhandled message of type: message.%s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
subtype);
return 1;
}
}
int slack_api_message(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *subtype, *channel, *user, *text, *ts;
json_object *attachments, *attachment, *fallback;
int i, rc;
subtype = json_object_object_get(message, "subtype");
if (!subtype)
{ /* normal message */
channel = json_object_object_get(message, "channel");
if (!json_valid(channel, workspace))
return 0;
user = json_object_object_get(message, "user");
if (!json_valid(user, workspace))
return 0;
text = json_object_object_get(message, "text");
if (!json_valid(text, workspace))
return 0;
ts = json_object_object_get(message, "ts");
if (!json_valid(ts, workspace))
return 0;
rc = slack_api_message_message_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user),
json_object_get_string(text),
json_object_get_string(ts));
attachments = json_object_object_get(message, "attachments");
if (json_valid(attachments, workspace))
{
for (i = json_object_array_length(attachments); i > 0; i--)
{
attachment = json_object_array_get_idx(attachments, i - 1);
if (!json_valid(attachment, workspace))
continue;
fallback = json_object_object_get(attachment, "fallback");
if (!json_valid(fallback, workspace))
continue;
slack_api_message_attachment_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user),
json_object_get_string(fallback),
json_object_get_string(ts));
}
}
return rc;
}
else
{ /* special message */
return slack_api_message_route_message(workspace,
json_object_get_string(subtype),
message);
}
}

@ -1,13 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_MESSAGE_H_
#define _SLACK_API_MESSAGE_H_
int slack_api_message(struct t_slack_workspace *workspace,
json_object *message);
void slack_api_message_init();
#endif /*SLACK_API_MESSAGE_H*/

@ -1,67 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <json.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-user.h"
#include "../slack-channel.h"
#include "../slack-api.h"
#include "slack-api-user-typing.h"
static const char *type = "user_typing";
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_user_typing_handle(struct t_slack_workspace *workspace,
const char *channel, const char *user)
{
struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user;
ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel)
return 1; /* silently ignore if channel hasn't been loaded yet */
ptr_user = slack_user_search(workspace, user);
if (!ptr_user)
return 1; /* silently ignore if user hasn't been loaded yet */
slack_channel_add_typing(ptr_channel, ptr_user);
return 1;
}
int slack_api_user_typing(struct t_slack_workspace *workspace,
json_object *message)
{
json_object *channel, *user;
channel = json_object_object_get(message, "channel");
if (!json_valid(channel, workspace))
return 0;
user = json_object_object_get(message, "user");
if (!json_valid(user, workspace))
return 0;
return slack_api_user_typing_handle(workspace,
json_object_get_string(channel),
json_object_get_string(user));
}

@ -1,11 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_API_USER_TYPING_H_
#define _SLACK_API_USER_TYPING_H_
int slack_api_user_typing(struct t_slack_workspace *workspace,
json_object *message);
#endif /*SLACK_API_USER_TYPING_H*/

@ -7,14 +7,14 @@
#include <string.h>
#include <weechat/weechat-plugin.h>
#include "xmpp.h"
#include "plugin.h"
//#include "xmpp-oauth.h"
//#include "xmpp-teaminfo.h"
//#include "xmpp-workspace.h"
//#include "xmpp-channel.h"
//#include "xmpp-buffer.h"
//#include "xmpp-message.h"
#include "xmpp-command.h"
#include "command.h"
//#include "request/xmpp-request-chat-memessage.h"
/*

@ -2,9 +2,9 @@
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _XMPP_COMMAND_H_
#define _XMPP_COMMAND_H_
#ifndef _WEECHAT_XMPP_COMMAND_H_
#define _WEECHAT_XMPP_COMMAND_H_
extern void xmpp_command_init();
#endif /*XMPP_COMMAND_H*/
#endif /*WEECHAT_XMPP_COMMAND_H*/

@ -7,8 +7,8 @@
#include <strophe.h>
#include <weechat/weechat-plugin.h>
#include "xmpp.h"
#include "xmpp-config.h"
#include "plugin.h"
#include "config.h"
struct t_config_file *xmpp_config_file;
@ -241,7 +241,7 @@ int xmpp_config_init()
struct t_config_section *ptr_section_server;
struct t_config_section *ptr_section_look;
xmpp_config_file = weechat_config_new(XMPP_CONFIG_NAME,
xmpp_config_file = weechat_config_new(WEECHAT_XMPP_CONFIG_NAME,
&xmpp_config_reload, NULL, NULL);
if(!xmpp_config_file)

@ -2,10 +2,10 @@
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _XMPP_CONFIG_H_
#define _XMPP_CONFIG_H_
#ifndef _WEECHAT_XMPP_CONFIG_H_
#define _WEECHAT_XMPP_CONFIG_H_
#define XMPP_CONFIG_NAME "xmpp"
#define WEECHAT_XMPP_CONFIG_NAME "xmpp"
enum t_xmpp_config_nick_completion
{
@ -56,4 +56,4 @@ extern int xmpp_config_read();
extern int xmpp_config_write();
extern void xmpp_config_free();
#endif /*XMPP_CONFIG_H*/
#endif /*WEECHAT_XMPP_CONFIG_H*/

@ -8,9 +8,9 @@
#include <strophe.h>
#include <weechat/weechat-plugin.h>
#include "xmpp.h"
#include "xmpp-config.h"
#include "xmpp-connection.h"
#include "plugin.h"
#include "config.h"
#include "connection.h"
//#include "api/xmpp-api-hello.h"
//#include "api/xmpp-api-error.h"
//#include "api/xmpp-api-message.h"
@ -30,7 +30,7 @@ void xmpp_log_emit_weechat(void *const userdata, const xmpp_log_level_t level, c
weechat_printf(
NULL,
_("%s%s/%s (%s): %s"),
weechat_prefix("error"), XMPP_PLUGIN_NAME, area,
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, area,
log_level_name[level], msg);
}

@ -2,8 +2,8 @@
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _XMPP_CONNECTION_H_
#define _XMPP_CONNECTION_H_
#ifndef _WEECHAT_XMPP_CONNECTION_H_
#define _WEECHAT_XMPP_CONNECTION_H_
extern xmpp_conn_t *xmpp_connection;
@ -18,4 +18,4 @@ int xmpp_connection_check_events(const void *pointer, void *data, int remaining_
int xmpp_connection_route_message(xmpp_conn_t *connection,
const char *type, json_object *message);
#endif /*XMPP_CONNECTION_H*/
#endif /*WEECHAT_XMPP_CONNECTION_H*/

@ -9,19 +9,19 @@
#include <json.h>
#include <weechat/weechat-plugin.h>
#include "xmpp.h"
#include "xmpp-config.h"
#include "xmpp-connection.h"
#include "xmpp-command.h"
#include "plugin.h"
#include "config.h"
#include "connection.h"
#include "command.h"
//#include "xmpp-workspace.h"
//#include "xmpp-buffer.h"
//#include "xmpp-completion.h"
WEECHAT_PLUGIN_NAME(XMPP_PLUGIN_NAME);
WEECHAT_PLUGIN_NAME(WEECHAT_XMPP_PLUGIN_NAME);
WEECHAT_PLUGIN_DESCRIPTION(N_("XMPP protocol"));
WEECHAT_PLUGIN_AUTHOR("bqv <weechat@fron.io>");
WEECHAT_PLUGIN_VERSION(XMPP_PLUGIN_VERSION);
WEECHAT_PLUGIN_VERSION(WEECHAT_XMPP_PLUGIN_VERSION);
WEECHAT_PLUGIN_LICENSE("MPL2");
WEECHAT_PLUGIN_PRIORITY(5500);

@ -2,13 +2,13 @@
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _XMPP_H_
#define _XMPP_H_
#ifndef _WEECHAT_XMPP_H_
#define _WEECHAT_XMPP_H_
#define weechat_plugin weechat_xmpp_plugin
#define XMPP_PLUGIN_NAME "xmpp"
#define XMPP_PLUGIN_VERSION "0.1"
#define WEECHAT_XMPP_PLUGIN_NAME "xmpp"
#define WEECHAT_XMPP_PLUGIN_VERSION "0.1"
extern struct t_weechat_plugin *weechat_xmpp_plugin;
#endif /*XMPP_H*/
#endif /*WEECHAT_XMPP_H*/

@ -1,272 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-channel.h"
#include "../slack-request.h"
#include "../slack-user.h"
#include "../request/slack-request-bots-info.h"
static const char *const endpoint = "/api/bots.info?"
"token=%s&bot=%s";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error retrieving bot info: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
//__asm__("int3");
return 0;
}
return 1;
}
static const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) retrieving bot info... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
char cursor[64];
json_object *response, *ok, *error, *members, *metadata;
json_object *user, *id, *name, *profile, *display_name, *next_cursor;
struct t_json_chunk *chunk_ptr;
chunk_count = 0;
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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))
{
// TODO: this
}
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: (%d) failed to retrieve users: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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_bots_info(
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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_REQUEST_BOTS_INFO_H_
#define _SLACK_REQUEST_BOTS_INFO_H_
struct t_slack_request *slack_request_bots_info(
struct t_slack_workspace *workspace,
const char *token, const char *cursor);
#endif /*SLACK_REQUEST_BOTS_INFO_H*/

@ -1,431 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#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=20";
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 const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) retrieving channels... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
char cursor[64];
json_object *response, *ok, *error, *channels, *metadata;
json_object *channel, *id, *name, *created;
json_object *is_general, *name_normalized, *is_shared, *is_org_shared, *is_member;
json_object *topic, *purpose, *is_archived;
json_object *sub_value, *sub_creator, *sub_last_set;
json_object *creator, *next_cursor;
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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))
{
continue;
}
id = json_object_object_get(channel, "id");
if (!json_valid(id, request->workspace))
{
continue;
}
name = json_object_object_get(channel, "name");
if (!json_valid(name, request->workspace))
{
continue;
}
new_channel = slack_channel_new(
request->workspace,
SLACK_CHANNEL_TYPE_CHANNEL,
json_object_get_string(id),
json_object_get_string(name));
created = json_object_object_get(channel, "created");
if (json_valid(created, request->workspace))
{
new_channel->created = json_object_get_int(created);
}
is_general = json_object_object_get(channel, "is_general");
if (json_valid(is_general, request->workspace))
{
new_channel->is_general = json_object_get_boolean(is_general);
}
name_normalized = json_object_object_get(channel, "name_normalized");
if (json_valid(name_normalized, request->workspace))
{
new_channel->name_normalized = strdup(
json_object_get_string(name_normalized));
}
is_shared = json_object_object_get(channel, "is_shared");
if (json_valid(is_shared, request->workspace))
{
new_channel->is_shared = json_object_get_boolean(is_shared);
}
is_org_shared = json_object_object_get(channel, "is_org_shared");
if (json_valid(is_org_shared, request->workspace))
{
new_channel->is_org_shared = json_object_get_boolean(is_org_shared);
}
is_member = json_object_object_get(channel, "is_member");
if (json_valid(is_member, request->workspace))
{
new_channel->is_member = json_object_get_boolean(is_member);
}
topic = json_object_object_get(channel, "topic");
if (json_valid(topic, request->workspace))
{
sub_value = json_object_object_get(topic, "value");
sub_creator = json_object_object_get(topic, "creator");
sub_last_set = json_object_object_get(topic, "last_set");
slack_channel_update_topic(new_channel,
json_valid(sub_value, request->workspace) ?
json_object_get_string(sub_value) :
NULL,
json_valid(sub_creator, request->workspace) ?
json_object_get_string(sub_creator) :
NULL,
json_valid(sub_last_set, request->workspace) ?
json_object_get_int(sub_last_set) :
0);
}
purpose = json_object_object_get(channel, "purpose");
if (json_valid(purpose, request->workspace))
{
sub_value = json_object_object_get(topic, "value");
sub_creator = json_object_object_get(topic, "creator");
sub_last_set = json_object_object_get(topic, "last_set");
slack_channel_update_purpose(new_channel,
json_valid(sub_value, request->workspace) ?
json_object_get_string(sub_value) :
NULL,
json_valid(sub_creator, request->workspace) ?
json_object_get_string(sub_creator) :
NULL,
json_valid(sub_last_set, request->workspace) ?
json_object_get_int(sub_last_set) :
0);
}
is_archived = json_object_object_get(response, "is_archived");
if (json_valid(is_archived, request->workspace))
{
new_channel->is_archived = json_object_get_boolean(is_archived);
}
creator = json_object_object_get(response, "creator");
if (json_valid(creator, request->workspace))
{
new_channel->creator = strdup(json_object_get_string(creator));
}
}
metadata = json_object_object_get(response, "response_metadata");
if (!json_valid(metadata, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
next_cursor = json_object_object_get(metadata, "next_cursor");
if (!json_valid(next_cursor, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
lws_urlencode(cursor, json_object_get_string(next_cursor), sizeof(cursor));
if (cursor[0])
{
struct t_slack_request *next_request;
next_request = slack_request_channels_list(request->workspace,
weechat_config_string(
request->workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]),
cursor);
if (next_request)
slack_workspace_register_request(request->workspace, next_request);
}
}
else
{
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: (%d) failed to retrieve channels: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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*/

@ -1,270 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-request.h"
#include "../slack-user.h"
#include "../request/slack-request-chat-memessage.h"
static const char *const endpoint = "/api/chat.meMessage?"
"token=%s&channel=%s&text=%s&";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error sending me-message: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
//__asm__("int3");
return 0;
}
return 1;
}
static const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) sending me-message... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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))
{
/* wait for websocket to catch up */
}
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: (%d) failed to send me-message: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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_chat_memessage(
struct t_slack_workspace *workspace,
const char *token, const char *channel,
const char *text)
{
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, channel, text) + 1;
request->uri = malloc(urilen);
snprintf(request->uri, urilen, endpoint, token, channel, text);
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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,13 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_REQUEST_CHAT_MEMESSAGE_H_
#define _SLACK_REQUEST_CHAT_MEMESSAGE_H_
struct t_slack_request *slack_request_chat_memessage(
struct t_slack_workspace *workspace,
const char *token, const char *channel,
const char *text);
#endif /*SLACK_REQUEST_CHAT_MEMESSAGE_H*/

@ -1,271 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-request.h"
#include "../slack-user.h"
#include "../request/slack-request-chat-postmessage.h"
static const char *const endpoint = "/api/chat.postMessage?"
"token=%s&channel=%s&text=%s&"
"as_user=true&link_names=true&mrkdwn=false&parse=full";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error posting message: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
//__asm__("int3");
return 0;
}
return 1;
}
static const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) posting message... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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))
{
/* wait for websocket to catch up */
}
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: (%d) failed to post message: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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_chat_postmessage(
struct t_slack_workspace *workspace,
const char *token, const char *channel,
const char *text)
{
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, channel, text) + 1;
request->uri = malloc(urilen);
snprintf(request->uri, urilen, endpoint, token, channel, text);
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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,13 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_REQUEST_CHAT_POSTMESSAGE_H_
#define _SLACK_REQUEST_CHAT_POSTMESSAGE_H_
struct t_slack_request *slack_request_chat_postmessage(
struct t_slack_workspace *workspace,
const char *token, const char *channel,
const char *text);
#endif /*SLACK_REQUEST_CHAT_POSTMESSAGE_H*/

@ -1,330 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-channel.h"
#include "../slack-request.h"
#include "../slack-user.h"
#include "../request/slack-request-conversations-members.h"
static const char *const endpoint = "/api/conversations.members?"
"token=%s&channel=%s&cursor=%s&limit=100";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error retrieving members: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
//__asm__("int3");
return 0;
}
return 1;
}
static const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
struct t_slack_channel *channel;
const char *channelid;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) retrieving members... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
char cursor[64];
json_object *response, *ok, *error, *members;
json_object *user, *metadata, *next_cursor;
struct t_json_chunk *chunk_ptr;
channelid = (const char *)request->pointer;
channel = slack_channel_search(request->workspace, channelid);
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
}
slack_channel_add_member(request->workspace,
channel,
json_object_get_string(user));
}
metadata = json_object_object_get(response, "response_metadata");
if (!json_valid(metadata, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
next_cursor = json_object_object_get(metadata, "next_cursor");
if (!json_valid(next_cursor, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
lws_urlencode(cursor, json_object_get_string(next_cursor), sizeof(cursor));
if (cursor[0])
{
struct t_slack_request *next_request;
next_request = slack_request_conversations_members(request->workspace,
weechat_config_string(
request->workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]),
channelid,
cursor);
if (next_request)
slack_workspace_register_request(request->workspace, next_request);
}
}
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: (%d) failed to retrieve users: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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_conversations_members(
struct t_slack_workspace *workspace,
const char *token, const char *channel,
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);
request->pointer = channel;
size_t urilen = snprintf(NULL, 0, endpoint, token, channel, cursor) + 1;
request->uri = malloc(urilen);
snprintf(request->uri, urilen, endpoint, token, channel, 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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,13 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_REQUEST_CONVERSATIONS_MEMBERS_H_
#define _SLACK_REQUEST_CONVERSATIONS_MEMBERS_H_
struct t_slack_request *slack_request_conversations_members(
struct t_slack_workspace *workspace,
const char *token, const char *channel,
const char *cursor);
#endif /*SLACK_REQUEST_CONVERSATIONS_MEMBERS_H*/

@ -1,287 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-request.h"
#include "../slack-channel.h"
#include "../request/slack-request-emoji-list.h"
static const char *const endpoint = "/api/emoji.list?"
"token=%s";
static inline int json_valid(json_object *object, struct t_slack_workspace *workspace)
{
if (!object)
{
weechat_printf(
workspace->buffer,
_("%s%s: error retrieving emoji: unexpected response from server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
//__asm__("int3");
return 0;
}
return 1;
}
static const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) retrieving emoji... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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, *emoji;
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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))
{
emoji = json_object_object_get(response, "emoji");
if (!json_valid(emoji, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
json_object_object_foreach(emoji, key, val)
{
if (!json_valid(val, request->workspace))
{
continue;
}
slack_workspace_add_emoji(
request->workspace,
key, json_object_get_string(val));
}
}
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: (%d) failed to retrieve emoji: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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_emoji_list(
struct t_slack_workspace *workspace,
const char *token)
{
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) + 1;
request->uri = malloc(urilen);
snprintf(request->uri, urilen, endpoint, token);
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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_REQUEST_EMOJI_LIST_H_
#define _SLACK_REQUEST_EMOJI_LIST_H_
struct t_slack_request *slack_request_emoji_list(
struct t_slack_workspace *workspace,
const char *token);
#endif /*SLACK_REQUEST_EMOJI_LIST_H*/

@ -1,375 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-channel.h"
#include "../slack-request.h"
#include "../slack-user.h"
#include "../request/slack-request-conversations-members.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=20";
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 const struct lws_protocols protocols[];
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;
struct lws_client_connect_info ccinfo;
int status;
switch (reason)
{
/* because we are protocols[0] ... */
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) error connecting to slack: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
in ? (char *)in : "(null)");
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) reconnecting..."),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
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);
break;
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
status = lws_http_client_http_response(wsi);
weechat_printf(
request->workspace->buffer,
_("%s%s: (%d) retrieving users... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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;
char cursor[64];
json_object *response, *ok, *error, *members;
json_object *user, *id, *name;
json_object *profile, *display_name, *bot_id;
json_object *metadata, *next_cursor;
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: (%d) got response: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx,
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--)
{
struct t_slack_user *new_user;
user = json_object_array_get_idx(members, i - 1);
if (!json_valid(user, request->workspace))
{
continue;
}
id = json_object_object_get(user, "id");
if (!json_valid(id, request->workspace))
{
continue;
}
name = json_object_object_get(user, "name");
if (!json_valid(name, request->workspace))
{
continue;
}
profile = json_object_object_get(user, "profile");
if (!json_valid(profile, request->workspace))
{
continue;
}
display_name = json_object_object_get(profile, "display_name");
if (!json_valid(display_name, request->workspace))
{
continue;
}
new_user = slack_user_new(request->workspace,
json_object_get_string(id),
json_object_get_string(display_name)[0] ?
json_object_get_string(display_name) :
json_object_get_string(name));
bot_id = json_object_object_get(profile, "bot_id");
if (json_valid(bot_id, request->workspace))
{
new_user->profile.bot_id = strdup(json_object_get_string(bot_id));
}
}
metadata = json_object_object_get(response, "response_metadata");
if (!json_valid(metadata, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
next_cursor = json_object_object_get(metadata, "next_cursor");
if (!json_valid(next_cursor, request->workspace))
{
json_object_put(response);
free(json_string);
return 0;
}
lws_urlencode(cursor, json_object_get_string(next_cursor), sizeof(cursor));
if (cursor[0])
{
struct t_slack_request *next_request;
next_request = slack_request_users_list(request->workspace,
weechat_config_string(
request->workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]),
cursor);
if (next_request)
slack_workspace_register_request(request->workspace, next_request);
}
else
{
struct t_slack_request *next_request;
struct t_slack_channel *ptr_channel;
for (ptr_channel = request->workspace->channels; ptr_channel;
ptr_channel = ptr_channel->next_channel)
{
next_request = slack_request_conversations_members(request->workspace,
weechat_config_string(
request->workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]),
ptr_channel->id,
cursor);
if (next_request)
slack_workspace_register_request(request->workspace, next_request);
}
}
}
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: (%d) failed to retrieve users: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL;
/* Does not doing this cause a leak?
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: (%d) error connecting to slack: lws init failed"),
weechat_prefix("error"), SLACK_PLUGIN_NAME, request->idx);
return NULL;
}
else
{
weechat_printf(
workspace->buffer,
_("%s%s: (%d) contacting slack.com:443"),
weechat_prefix("network"), SLACK_PLUGIN_NAME, request->idx);
}
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;
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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*/

@ -1,164 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <string.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
#include "slack-channel.h"
#include "slack-buffer.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 */
}
char *slack_buffer_typing_bar_cb(const void *pointer,
void *data,
struct t_gui_bar_item *item,
struct t_gui_window *window,
struct t_gui_buffer *buffer,
struct t_hashtable *extra_info)
{
struct t_slack_channel_typing *ptr_typing;
struct t_slack_workspace *workspace;
struct t_slack_channel *channel;
char notification[256];
unsigned typecount;
(void) pointer;
(void) data;
(void) item;
(void) window;
(void) extra_info;
workspace = NULL;
channel = NULL;
slack_buffer_get_workspace_and_channel(buffer, &workspace, &channel);
if (!channel)
return strdup("");
typecount = 0;
for (ptr_typing = channel->typings; ptr_typing;
ptr_typing = ptr_typing->next_typing)
{
switch (++typecount)
{
case 1:
strcpy(notification, ptr_typing->name);
break;
case 2:
strcat(notification, ", ");
strcat(notification, ptr_typing->name);
break;
case 3:
default:
strcpy(notification, "Several people");
break;
}
}
if (typecount)
{
strcat(notification, NG_(" is typing...",
" are typing...",
typecount));
return strdup(notification);
}
else
{
return strdup("");
}
}
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);
(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);
}
ptr_workspace->buffer = NULL;
}
return WEECHAT_RC_OK;
}

@ -1,27 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_BUFFER_H_
#define _SLACK_BUFFER_H_
void slack_buffer_get_workspace_and_channel(struct t_gui_buffer *buffer,
struct t_slack_workspace **workspace,
struct t_slack_channel **channel);
char *slack_buffer_typing_bar_cb(const void *pointer,
void *data,
struct t_gui_bar_item *item,
struct t_gui_window *window,
struct t_gui_buffer *buffer,
struct t_hashtable *extra_info);
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);
#endif /*SLACK_BUFFER_H*/

@ -1,642 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
#include "slack-user.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;
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
{
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;
}
void slack_channel_add_nicklist_groups(struct t_slack_workspace *workspace,
struct t_slack_channel *channel)
{
struct t_gui_buffer *ptr_buffer;
char str_group[32];
if (channel && channel->type == SLACK_CHANNEL_TYPE_MPIM)
return;
if (channel && channel->type == SLACK_CHANNEL_TYPE_IM)
return;
ptr_buffer = channel ? channel->buffer : workspace->buffer;
snprintf(str_group, sizeof(str_group), "%03d|%s",
000, "+");
weechat_nicklist_add_group(ptr_buffer, NULL, str_group,
"weechat.color.nicklist_group", 1);
snprintf(str_group, sizeof(str_group), "%03d|%s",
999, "...");
weechat_nicklist_add_group(ptr_buffer, NULL, str_group,
"weechat.color.nicklist_group", 1);
}
struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
enum t_slack_channel_type type,
const char *id, const char *name)
{
struct t_slack_channel *new_channel, *ptr_channel;
struct t_gui_buffer *ptr_buffer;
struct t_hook *typing_timer;
char buffer_name[SLACK_CHANNEL_NAME_MAX_LEN + 2];
if (!workspace || !id || !name || !name[0])
return NULL;
ptr_channel = slack_channel_search(workspace, id);
if (ptr_channel)
{
return ptr_channel;
}
buffer_name[0] = '#';
strncpy(&buffer_name[1], name, SLACK_CHANNEL_NAME_MAX_LEN + 1);
ptr_buffer = slack_channel_create_buffer(workspace, type, buffer_name);
if (!ptr_buffer)
return NULL;
if ((new_channel = malloc(sizeof(*new_channel))) == NULL)
return NULL;
typing_timer = weechat_hook_timer(1 * 1000, 0, 0,
&slack_channel_typing_cb,
new_channel, 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->typing_hook_timer = typing_timer;
new_channel->members_speaking[0] = NULL;
new_channel->members_speaking[1] = NULL;
new_channel->typings = NULL;
new_channel->last_typing = NULL;
new_channel->members = NULL;
new_channel->last_member = NULL;
new_channel->buffer = ptr_buffer;
new_channel->buffer_as_string = NULL;
new_channel->prev_channel = workspace->last_channel;
new_channel->next_channel = NULL;
if (workspace->last_channel)
(workspace->last_channel)->next_channel = new_channel;
else
workspace->channels = new_channel;
workspace->last_channel = new_channel;
return new_channel;
}
void slack_channel_member_speaking_add_to_list(struct t_slack_channel *channel,
const char *nick,
int highlight)
{
int size, to_remove, i;
struct t_weelist_item *ptr_item;
/* create list if it does not exist */
if (!channel->members_speaking[highlight])
channel->members_speaking[highlight] = weechat_list_new();
/* remove item if it was already in list */
ptr_item = weechat_list_casesearch(channel->members_speaking[highlight], nick);
if (ptr_item)
weechat_list_remove(channel->members_speaking[highlight], ptr_item);
/* add nick in list */
weechat_list_add(channel->members_speaking[highlight], nick,
WEECHAT_LIST_POS_END, NULL);
/* reduce list size if it's too big */
size = weechat_list_size(channel->members_speaking[highlight]);
if (size > SLACK_CHANNEL_MEMBERS_SPEAKING_LIMIT)
{
to_remove = size - SLACK_CHANNEL_MEMBERS_SPEAKING_LIMIT;
for (i = 0; i < to_remove; i++)
{
weechat_list_remove(
channel->members_speaking[highlight],
weechat_list_get(channel->members_speaking[highlight], 0));
}
}
}
void slack_channel_member_speaking_add(struct t_slack_channel *channel,
const char *nick, int highlight)
{
if (highlight < 0)
highlight = 0;
if (highlight > 1)
highlight = 1;
if (highlight)
slack_channel_member_speaking_add_to_list(channel, nick, 1);
slack_channel_member_speaking_add_to_list(channel, nick, 0);
}
void slack_channel_member_speaking_rename(struct t_slack_channel *channel,
const char *old_nick,
const char *new_nick)
{
struct t_weelist_item *ptr_item;
int i;
for (i = 0; i < 2; i++)
{
if (channel->members_speaking[i])
{
ptr_item = weechat_list_search(channel->members_speaking[i], old_nick);
if (ptr_item)
weechat_list_set(ptr_item, new_nick);
}
}
}
void slack_channel_member_speaking_rename_if_present(struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
const char *nick)
{
struct t_weelist_item *ptr_item;
int i, j, list_size;
(void) workspace;
for (i = 0; i < 2; i++)
{
if (channel->members_speaking[i])
{
list_size = weechat_list_size(channel->members_speaking[i]);
for (j = 0; j < list_size; j++)
{
ptr_item = weechat_list_get (channel->members_speaking[i], j);
if (ptr_item && (strcasecmp(weechat_list_string(ptr_item), nick) == 0))
weechat_list_set(ptr_item, nick);
}
}
}
}
void slack_channel_typing_free(struct t_slack_channel *channel,
struct t_slack_channel_typing *typing)
{
struct t_slack_channel_typing *new_typings;
if (!channel || !typing)
return;
/* remove typing from typings list */
if (channel->last_typing == typing)
channel->last_typing = typing->prev_typing;
if (typing->prev_typing)
{
(typing->prev_typing)->next_typing = typing->next_typing;
new_typings = channel->typings;
}
else
new_typings = typing->next_typing;
if (typing->next_typing)
(typing->next_typing)->prev_typing = typing->prev_typing;
/* free typing data */
if (typing->id)
free(typing->id);
if (typing->name)
free(typing->name);
free(typing);
channel->typings = new_typings;
}
void slack_channel_typing_free_all(struct t_slack_channel *channel)
{
while (channel->typings)
slack_channel_typing_free(channel, channel->typings);
}
int slack_channel_typing_cb(const void *pointer,
void *data,
int remaining_calls)
{
struct t_slack_channel_typing *ptr_typing, *next_typing;
struct t_slack_channel *channel;
const char *localvar;
unsigned typecount;
time_t now;
(void) data;
(void) remaining_calls;
if (!pointer)
return WEECHAT_RC_ERROR;
channel = (struct t_slack_channel *)pointer;
now = time(NULL);
typecount = 0;
for (ptr_typing = channel->typings; ptr_typing;
ptr_typing = ptr_typing->next_typing)
{
next_typing = ptr_typing->next_typing;
while (ptr_typing && now - ptr_typing->ts > 5)
{
slack_channel_typing_free(channel, ptr_typing);
ptr_typing = next_typing;
if (ptr_typing)
next_typing = ptr_typing->next_typing;
}
if (!ptr_typing)
break;
typecount++;
}
localvar = weechat_buffer_get_string(channel->buffer, "localvar_typing");
if (!localvar || strncmp(localvar, typecount > 0 ? "1" : "0", 1) != 0)
weechat_buffer_set(channel->buffer,
"localvar_set_typing",
typecount > 0 ? "1" : "0");
weechat_bar_item_update("slack_typing");
return WEECHAT_RC_OK;
}
struct t_slack_channel_typing *slack_channel_typing_search(
struct t_slack_channel *channel,
const char *id)
{
struct t_slack_channel_typing *ptr_typing;
if (!channel || !id)
return NULL;
for (ptr_typing = channel->typings; ptr_typing;
ptr_typing = ptr_typing->next_typing)
{
if (weechat_strcasecmp(ptr_typing->id, id) == 0)
return ptr_typing;
}
return NULL;
}
void slack_channel_add_typing(struct t_slack_channel *channel,
struct t_slack_user *user)
{
struct t_slack_channel_typing *new_typing;
new_typing = slack_channel_typing_search(channel, user->id);
if (!new_typing)
{
new_typing = malloc(sizeof(*new_typing));
new_typing->id = strdup(user->id);
new_typing->name = strdup(user->profile.display_name);
new_typing->prev_typing = channel->last_typing;
new_typing->next_typing = NULL;
if (channel->last_typing)
(channel->last_typing)->next_typing = new_typing;
else
channel->typings = new_typing;
channel->last_typing = new_typing;
}
new_typing->ts = time(NULL);
slack_channel_typing_cb(channel, NULL, 0);
}
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 hooks */
if (channel->typing_hook_timer)
weechat_unhook(channel->typing_hook_timer);
/* free linked lists */
slack_channel_typing_free_all(channel);
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->members_speaking[0])
weechat_list_free(channel->members_speaking[0]);
if (channel->members_speaking[1])
weechat_list_free(channel->members_speaking[1]);
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);
}
void slack_channel_update_topic(struct t_slack_channel *channel,
const char* topic,
const char* creator,
int last_set)
{
if (channel->topic.value)
free(channel->topic.value);
if (channel->topic.creator)
free(channel->topic.creator);
channel->topic.value = (topic) ? strdup(topic) : NULL;
channel->topic.creator = (creator) ? strdup(creator) : NULL;
channel->topic.last_set = last_set;
if (channel->topic.value)
weechat_buffer_set(channel->buffer, "title", topic);
else
weechat_buffer_set(channel->buffer, "title", "");
}
void slack_channel_update_purpose(struct t_slack_channel *channel,
const char* purpose,
const char* creator,
int last_set)
{
if (channel->purpose.value)
free(channel->purpose.value);
if (channel->purpose.creator)
free(channel->purpose.creator);
channel->purpose.value = (purpose) ? strdup(purpose) : NULL;
channel->purpose.creator = (creator) ? strdup(creator) : NULL;
channel->purpose.last_set = last_set;
}
struct t_slack_channel_member *slack_channel_add_member(
struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
const char *id)
{
struct t_slack_channel_member *member;
struct t_slack_user *user;
member = malloc(sizeof(struct t_slack_channel_member));
member->id = strdup(id);
member->prev_member = channel->last_member;
member->next_member = NULL;
if (channel->last_member)
(channel->last_member)->next_member = member;
else
channel->members = member;
channel->last_member = member;
user = slack_user_search(workspace, id);
if (user)
slack_user_nicklist_add(workspace, channel, user);
return member;
}

@ -1,147 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_CHANNEL_H_
#define _SLACK_CHANNEL_H_
#define SLACK_CHANNEL_MEMBERS_SPEAKING_LIMIT 128
#define SLACK_CHANNEL_NAME_MAX_LEN 22
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_typing
{
char *id;
char *name;
time_t ts;
struct t_slack_channel_typing *prev_typing;
struct t_slack_channel_typing *next_typing;
};
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;
time_t last_set;
};
struct t_slack_channel_purpose
{
char *value;
char *creator;
time_t last_set;
};
struct t_slack_channel
{
enum t_slack_channel_type type;
char *id;
char *name;
time_t 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_hook *typing_hook_timer;
struct t_weelist *members_speaking[2];
struct t_slack_channel_typing *typings;
struct t_slack_channel_typing *last_typing;
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);
void slack_channel_add_nicklist_groups(struct t_slack_workspace *workspace,
struct t_slack_channel *channel);
struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
enum t_slack_channel_type type,
const char *id, const char *name);
void slack_channel_member_speaking_add(struct t_slack_channel *channel,
const char *nick, int highlight);
void slack_channel_member_speaking_rename(struct t_slack_channel *channel,
const char *old_nick,
const char *new_nick);
void slack_channel_member_speaking_rename_if_present(struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
const char *nick);
void slack_channel_typing_free(struct t_slack_channel *channel,
struct t_slack_channel_typing *typing);
void slack_channel_typing_free_all(struct t_slack_channel *channel);
int slack_channel_typing_cb(const void *pointer,
void *data,
int remaining_calls);
struct t_slack_channel_typing *slack_channel_typing_search(
struct t_slack_channel *channel,
const char *id);
void slack_channel_add_typing(struct t_slack_channel *channel,
struct t_slack_user *user);
void slack_channel_free_all(struct t_slack_workspace *workspace);
void slack_channel_update_topic(struct t_slack_channel *channel,
const char* title,
const char* creator,
int last_set);
void slack_channel_update_purpose(struct t_slack_channel *channel,
const char* purpose,
const char* creator,
int last_set);
struct t_slack_channel_member *slack_channel_add_member(
struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
const char *id);
#endif /*SLACK_CHANNEL_H*/

@ -1,162 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-config.h"
#include "slack-emoji.h"
#include "slack-workspace.h"
#include "slack-channel.h"
#include "slack-user.h"
#include "slack-buffer.h"
#include "slack-completion.h"
void slack_completion_channel_nicks_add_speakers(struct t_gui_completion *completion,
struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
int highlight)
{
struct t_slack_user *user;
const char *member;
int list_size, i;
if (channel->members_speaking[highlight])
{
list_size = weechat_list_size(channel->members_speaking[highlight]);
for (i = 0; i < list_size; i++)
{
member = weechat_list_string (
weechat_list_get(channel->members_speaking[highlight], i));
if (member)
{
user = slack_user_search(workspace, member);
if (user)
weechat_hook_completion_list_add(completion,
user->profile.display_name,
1, WEECHAT_LIST_POS_BEGINNING);
}
}
}
}
int slack_completion_channel_nicks_cb(const void *pointer, void *data,
const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
struct t_slack_workspace *ptr_workspace;
struct t_slack_channel *ptr_channel;
struct t_slack_channel_member *ptr_member;
struct t_slack_user *ptr_user;
(void) pointer;
(void) data;
(void) completion_item;
ptr_workspace = NULL;
ptr_channel = NULL;
slack_buffer_get_workspace_and_channel(buffer, &ptr_workspace, &ptr_channel);
if (ptr_channel)
{
switch (ptr_channel->type)
{
case SLACK_CHANNEL_TYPE_CHANNEL:
case SLACK_CHANNEL_TYPE_GROUP:
case SLACK_CHANNEL_TYPE_MPIM:
case SLACK_CHANNEL_TYPE_IM:
for (ptr_member = ptr_channel->members; ptr_member;
ptr_member = ptr_member->next_member)
{
ptr_user = slack_user_search(ptr_workspace, ptr_member->id);
if (ptr_user)
weechat_hook_completion_list_add(completion,
ptr_user->profile.display_name,
1, WEECHAT_LIST_POS_SORT);
}
/* add recent speakers on channel */
if (weechat_config_integer(slack_config_look_nick_completion_smart) == SLACK_CONFIG_NICK_COMPLETION_SMART_SPEAKERS)
{
slack_completion_channel_nicks_add_speakers(completion, ptr_workspace, ptr_channel, 0);
}
/* add members whose make highlights on me recently on this channel */
if (weechat_config_integer(slack_config_look_nick_completion_smart) == SLACK_CONFIG_NICK_COMPLETION_SMART_SPEAKERS_HIGHLIGHTS)
{
slack_completion_channel_nicks_add_speakers(completion, ptr_workspace, ptr_channel, 1);
}
/* add self member at the end */
weechat_hook_completion_list_add(completion,
ptr_workspace->nick,
1, WEECHAT_LIST_POS_END);
break;
}
}
return WEECHAT_RC_OK;
}
int slack_completion_workspaces_cb(const void *pointer, void *data,
const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
struct t_slack_workspace *ptr_workspace;
(void) pointer;
(void) data;
(void) completion_item;
(void) buffer;
for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace)
{
weechat_hook_completion_list_add(completion, ptr_workspace->domain,
0, WEECHAT_LIST_POS_SORT);
}
return WEECHAT_RC_OK;
}
void slack_completion_init()
{
struct t_config_option *option;
const char *default_template;
weechat_hook_completion ("nick",
N_("nicks of current Slack channel"),
&slack_completion_channel_nicks_cb,
NULL, NULL);
weechat_hook_completion("slack_workspace",
N_("slack workspaces"),
&slack_completion_workspaces_cb,
NULL, NULL);
weechat_hook_completion("slack_emoji",
N_("slack emoji"),
&slack_emoji_complete_by_name_cb,
NULL, NULL);
option = weechat_config_get("weechat.completion.default_template");
default_template = weechat_config_string(option);
if (!weechat_strcasestr(default_template, "%(slack_emoji)"))
{
size_t length = snprintf(NULL, 0, "%s|%s",
default_template,
"%(slack_emoji)") + 1;
char *new_template = malloc(length);
snprintf(new_template, length, "%s|%s",
default_template,
"%(slack_emoji)");
weechat_config_option_set(option, new_template, 1);
free(new_template);
}
}

@ -1,10 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_COMPLETION_H_
#define _SLACK_COMPLETION_H_
void slack_completion_init();
#endif /*SLACK_COMPLETION_H*/

@ -1,289 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
#include "slack-channel.h"
#include "slack-buffer.h"
#include "slack-emoji.h"
#include "slack-emoji.inc"
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
static int emoji_byname_cmp(const void *p1, const void *p2)
{
return strcasecmp(((struct t_slack_emoji_by_name *)p1)->name,
((struct t_slack_emoji_by_name *)p2)->name);
}
static int emoji_bytext_cmp(const void *p1, const void *p2)
{
return strcasecmp(((struct t_slack_emoji_by_text *)p1)->text,
((struct t_slack_emoji_by_text *)p2)->text);
}
static size_t modified_wagner_fischer(const char *src, const char *targ)
{
size_t len = strlen(targ) + 1;
size_t above[len], below[len];
for (size_t *k = above, c = 0; k < above + len; ++k, ++c) *k = c;
const char *src_at = src, *targ_at;
for (size_t j = 1; j < strlen(src) + 1; ++j)
{
*below = j;
targ_at = targ;
for (size_t *d = above, *a = above + 1, *l = below, *c = below + 1;
c < below + len; ++d, ++a, ++l, ++c)
{
/* |-------------replace-----------| |isrt| |delt| */
*c = MIN( *src_at == *targ_at ? *d : *d + 1, MIN( *a + 0, *l + 1 ) );
++targ_at;
}
for (size_t *a = above, *b = below; a < above + len; ++a, ++b) *a = *b;
++src_at;
}
return above[len-1];
}
static size_t longest_common_substring(const char *X, const char *Y)
{
const size_t n = strlen(X);
const size_t m = strlen(Y);
size_t i, j, result = 0;
size_t **L;
L = malloc(sizeof(size_t *) * (n + 1));
L[0] = malloc(sizeof(size_t) * (m + 1) * (n + 1));
for (i = 0; i <= n; i++)
L[i] = (*L + (m + 1) * i);
/* Following steps build L[n+1][m+1] in bottom up fashion. Note
that L[i][j] contains length of LCS of X[0..i-1] and Y[0..j-1] */
for (i = 0; i <= n; i++)
{
for (j = 0; j <= m; j++)
{
if (i == 0 || j == 0)
{
L[i][j] = 0;
}
else if (X[i-1] == Y[j-1])
{
L[i][j] = L[i - 1][j - 1] + 1;
if (result < L[i][j])
result = L[i][j];
}
else
{
L[i][j] = 0;
}
}
}
/* result now contains length of LCS for X[0..n-1] and Y[0..m-1] */
free(L[0]);
free(L);
return result;
}
int slack_emoji_complete_by_name_cb(const void *pointer, void *data,
const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion)
{
struct t_slack_workspace_emoji *ptr_emoji;
struct t_slack_workspace *workspace;
struct t_slack_channel *channel;
(void) pointer;
(void) data;
(void) completion_item;
workspace = NULL;
slack_buffer_get_workspace_and_channel(buffer, &workspace, &channel);
size_t i, emoji_count = sizeof(slack_emoji_by_name)
/ sizeof(struct t_slack_emoji_by_name);
if (workspace)
{
for (ptr_emoji = workspace->emoji; ptr_emoji;
ptr_emoji = ptr_emoji->next_emoji)
weechat_hook_completion_list_add(completion,
ptr_emoji->name,
0, WEECHAT_LIST_POS_END);
for (i = 0; i < emoji_count; i++)
weechat_hook_completion_list_add(completion,
slack_emoji_by_name[i].name,
0, WEECHAT_LIST_POS_END);
}
return WEECHAT_RC_OK;
}
int slack_emoji_input_complete_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *command)
{
struct t_slack_emoji_by_name *closest_emoji;
int input_pos, input_length, start, end;
char *new_string, *word, *new_pos;
const char *input_string;
(void) pointer;
(void) data;
(void) command;
input_string = weechat_buffer_get_string(buffer, "input");
input_length = strlen(input_string);
input_pos = weechat_buffer_get_integer(buffer, "input_pos");
for (start = input_pos; start > 0 && input_string[start] != ':'; start--)
if (input_string[start] == ' ') { break; }
for (end = input_pos; end < input_length && input_string[end] != ' '; end++)
if (input_string[end] == ':') { end++; break; }
if (input_string[start] != ':')
return WEECHAT_RC_OK;
else
word = strndup(&input_string[start], end - start);
size_t emoji_count = sizeof(slack_emoji_by_name)
/ sizeof(struct t_slack_emoji_by_name);
closest_emoji = malloc(sizeof(slack_emoji_by_name));
memcpy(closest_emoji, slack_emoji_by_name,
sizeof(slack_emoji_by_name));
int edit_dist_cmp(const void *p1, const void *p2)
{
const struct t_slack_emoji_by_name *e1 = p1;
const struct t_slack_emoji_by_name *e2 = p2;
size_t d1 = modified_wagner_fischer(e1->name, word);
size_t d2 = modified_wagner_fischer(e2->name, word);
if (d1 == d2)
{
size_t l1 = longest_common_substring(e1->name, word);
size_t l2 = longest_common_substring(e2->name, word);
return (l1 < l2) - (l1 > l2);
}
return (d1 > d2) - (d1 < d2);
};
qsort(closest_emoji, emoji_count,
sizeof(struct t_slack_emoji_by_name),
edit_dist_cmp);
size_t new_length = snprintf(NULL, 0, "%.*s%s%s",
start, input_string,
closest_emoji[0].name,
&input_string[end]) + 1;
new_string = malloc(new_length);
snprintf(new_string, new_length, "%.*s%s%s",
start, input_string,
closest_emoji[0].name,
&input_string[end]);
weechat_buffer_set(buffer, "input", new_string);
size_t new_pos_len = snprintf(NULL, 0, "%lu",
(unsigned long)(start +
strlen(closest_emoji[0].name) - 1));
new_pos = malloc(new_pos_len);
snprintf(new_pos, new_pos_len, "%lu",
(unsigned long)(start +
strlen(closest_emoji[0].name) - 1));
weechat_buffer_set(buffer, "input_pos", new_pos);
free(new_pos);
free(new_string);
free(closest_emoji);
free(word);
return WEECHAT_RC_OK_EAT;
}
int slack_emoji_input_replace_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *command)
{
(void) pointer;
(void) data;
(void) buffer;
(void) command;
/* TBI */
return WEECHAT_RC_OK;
}
const char *slack_emoji_get_unicode_by_name(const char *name)
{
struct t_slack_emoji_by_name *result;
struct t_slack_emoji_by_name key;
key.name = name;
size_t emoji_count = sizeof(slack_emoji_by_name)
/ sizeof(struct t_slack_emoji_by_name);
result = (struct t_slack_emoji_by_name *)bsearch(
&key, slack_emoji_by_name, emoji_count,
sizeof(struct t_slack_emoji_by_name),
emoji_byname_cmp);
return result->unicode;
}
const char *slack_emoji_get_unicode_by_text(const char *text)
{
struct t_slack_emoji_by_text *result;
struct t_slack_emoji_by_text key;
key.text = text;
size_t emoji_count = sizeof(slack_emoji_by_text)
/ sizeof(struct t_slack_emoji_by_text);
result = (struct t_slack_emoji_by_text *)bsearch(
&key, slack_emoji_by_text, emoji_count,
sizeof(struct t_slack_emoji_by_text),
emoji_bytext_cmp);
return result->unicode;
}
const char *slack_emoji_get_text_by_name(const char *name)
{
struct t_slack_emoji_by_name *result;
struct t_slack_emoji_by_name key;
key.name = name;
size_t emoji_count = sizeof(slack_emoji_by_name)
/ sizeof(struct t_slack_emoji_by_name);
result = (struct t_slack_emoji_by_name *)bsearch(
&key, slack_emoji_by_name, emoji_count,
sizeof(struct t_slack_emoji_by_name),
emoji_byname_cmp);
return result->text_to;
}
const char *slack_emoji_get_name_by_text(const char *text)
{
struct t_slack_emoji_by_text *result;
struct t_slack_emoji_by_text key;
key.text = text;
size_t emoji_count = sizeof(slack_emoji_by_text)
/ sizeof(struct t_slack_emoji_by_text);
result = (struct t_slack_emoji_by_text *)bsearch(
&key, slack_emoji_by_text, emoji_count,
sizeof(struct t_slack_emoji_by_text),
emoji_bytext_cmp);
return result->name_to;
}

@ -1,29 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_EMOJI_H_
#define _SLACK_EMOJI_H_
int slack_emoji_complete_by_name_cb(const void *pointer, void *data,
const char *completion_item,
struct t_gui_buffer *buffer,
struct t_gui_completion *completion);
int slack_emoji_input_complete_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *command);
int slack_emoji_input_replace_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *command);
const char *slack_emoji_get_unicode_by_name(const char *name);
const char *slack_emoji_get_unicode_by_text(const char *text);
const char *slack_emoji_get_text_by_name(const char *name);
const char *slack_emoji_get_name_by_text(const char *text);
#endif /*SLACK_EMOJI_H*/

File diff suppressed because it is too large Load Diff

@ -1,77 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <stdlib.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
#include "slack-channel.h"
#include "slack-buffer.h"
#include "slack-request.h"
#include "slack-message.h"
#include "slack-input.h"
#include "request/slack-request-chat-postmessage.h"
int slack_input_data(struct t_gui_buffer *buffer, const char *input_data)
{
struct t_slack_workspace *workspace = NULL;
struct t_slack_channel *channel = NULL;
struct t_slack_request *request;
char *text;
slack_buffer_get_workspace_and_channel(buffer, &workspace, &channel);
if (!workspace)
return WEECHAT_RC_ERROR;
if (channel)
{
if (!workspace->is_connected)
{
weechat_printf(buffer,
_("%s%s: you are not connected to server"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return WEECHAT_RC_OK;
}
text = malloc(SLACK_MESSAGE_MAX_LENGTH);
if (!text)
{
weechat_printf(buffer,
_("%s%s: error allocating string"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return WEECHAT_RC_ERROR;
}
lws_urlencode(text, input_data, SLACK_MESSAGE_MAX_LENGTH);
request = slack_request_chat_postmessage(workspace,
weechat_config_string(
workspace->options[SLACK_WORKSPACE_OPTION_TOKEN]),
channel->id, text);
if (request)
slack_workspace_register_request(workspace, request);
free(text);
}
else
{
weechat_printf(buffer,
_("%s%s: this buffer is not a channel!"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
}
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);
}

@ -1,12 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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*/

@ -1,249 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <regex.h>
#include "../weechat-plugin.h"
#include "../slack.h"
#include "../slack-workspace.h"
#include "../slack-channel.h"
#include "../slack-user.h"
#include "../slack-message.h"
static const char format_regex[] = "<([^>]*?)>";
static const size_t max_groups = 2;
char *slack_message_translate_code(struct t_slack_workspace *workspace,
const char *code)
{
struct t_slack_channel *channel;
struct t_slack_user *user;
size_t resultlen;
char *identifier, *alttext, *result, *symbol, *prefix;
identifier = strdup(code);
alttext = strchr(identifier, '|');
if (alttext)
*alttext++ = '\0';
switch (identifier[0])
{
case '#': /* channel */
if (alttext)
{
prefix = "#";
symbol = strdup(alttext);
}
else
{
channel = slack_channel_search(workspace, identifier+1);
if (channel)
{
prefix = "#";
symbol = strdup(channel->name);
}
else
{
prefix = "Channel:";
symbol = strdup(identifier+1);
}
}
break;
case '@': /* user */
if (alttext)
{
prefix = "@";
symbol = strdup(alttext);
}
else
{
user = slack_user_search(workspace, identifier+1);
if (user)
{
prefix = "@";
symbol = strdup(user->profile.display_name);
}
else
{
prefix = "User:";
symbol = strdup(identifier+1);
}
}
break;
case '!': /* special */
if (alttext)
{
prefix = "@";
symbol = strdup(alttext);
}
else
{
prefix = "@";
symbol = strdup(identifier+1);
}
break;
default: /* url */
prefix = "";
symbol = strdup(code);
break;
}
free(identifier);
resultlen = snprintf(NULL, 0, "%s%s%s%s", weechat_color("chat_nick"), prefix, symbol, weechat_color("reset")) + 1;
result = malloc(resultlen);
snprintf(result, resultlen, "%s%s%s%s", weechat_color("chat_nick"), prefix, symbol, weechat_color("reset"));
free(symbol);
return result;
}
void slack_message_htmldecode(char *dest, const char *src, size_t n)
{
size_t i, j;
for (i = 0, j = 0; i < n; i++, j++)
switch (src[i])
{
case '\0':
dest[j] = '\0';
return;
case '&':
if (src[i+1] == 'g' &&
src[i+2] == 't' &&
src[i+3] == ';')
{
dest[j] = '>';
i += 3;
break;
}
else if (src[i+1] == 'l' &&
src[i+2] == 't' &&
src[i+3] == ';')
{
dest[j] = '<';
i += 3;
break;
}
else if (src[i+1] == 'a' &&
src[i+2] == 'm' &&
src[i+3] == 'p' &&
src[i+4] == ';')
{
dest[j] = '&';
i += 4;
break;
}
/* fallthrough */
default:
dest[j] = src[i];
break;
}
dest[j-1] = '\0';
return;
}
char *slack_message_decode(struct t_slack_workspace *workspace,
const char *text)
{
int rc;
regex_t reg;
regmatch_t groups[max_groups];
char msgbuf[100];
char *decoded_text;
const char *cursor;
size_t offset;
if ((rc = regcomp(&reg, format_regex, REG_EXTENDED)))
{
regerror(rc, &reg, msgbuf, sizeof(msgbuf));
weechat_printf(
workspace->buffer,
_("%s%s: error compiling message formatting regex: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
msgbuf);
return strdup(text);
}
decoded_text = malloc(SLACK_MESSAGE_MAX_LENGTH);
if (!decoded_text)
{
regfree(&reg);
weechat_printf(
workspace->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return strdup(text);
}
decoded_text[0] = '\0';
for (cursor = text; regexec(&reg, cursor, max_groups, groups, 0) == 0; cursor += offset)
{
offset = groups[0].rm_eo;
char *copy = strdup(cursor);
if (!copy)
{
regfree(&reg);
free(decoded_text);
weechat_printf(
workspace->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return strdup(text);
}
copy[groups[1].rm_eo] = '\0';
char *match = strdup(copy + groups[1].rm_so);
if (!match)
{
free(copy);
regfree(&reg);
free(decoded_text);
weechat_printf(
workspace->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return strdup(text);
}
copy[groups[0].rm_so] = '\0';
char *prematch = strdup(copy);
if (!prematch)
{
free(match);
free(copy);
regfree(&reg);
free(decoded_text);
weechat_printf(
workspace->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return strdup(text);
}
free(copy);
strncat(decoded_text, prematch,
SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
free(prematch);
char *replacement = slack_message_translate_code(workspace, match);
free(match);
strncat(decoded_text, replacement,
SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
free(replacement);
}
strncat(decoded_text, cursor,
SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
slack_message_htmldecode(decoded_text, decoded_text,
SLACK_MESSAGE_MAX_LENGTH);
regfree(&reg);
return decoded_text;
}

@ -1,13 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_MESSAGE_H_
#define _SLACK_MESSAGE_H_
#define SLACK_MESSAGE_MAX_LENGTH 40000
char *slack_message_decode(struct t_slack_workspace *workspace,
const char *text);
#endif /*SLACK_MESSAGE_H*/

@ -1,245 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <string.h>
#include <libwebsockets.h>
#include <json.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-oauth.h"
static void (*weechat_callback)(char *token);
static const char *const endpoint = "/api/oauth.access?"
"client_id=%s&client_secret=%s&code=%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_oauth_hook_timer = NULL;
static inline int json_valid(json_object *object)
{
if (!object)
{
weechat_printf(
NULL,
_("%s%s: error retrieving token: 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 token... (%d)"),
weechat_prefix("network"), SLACK_PLUGIN_NAME,
status);
break;
/* chunks of chunked content, with header removed */
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ:
{
char *json_string = weechat_strndup(in, (int)len);
json_object *response, *ok, *error, *token;
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))
{
token = json_object_object_get(response, "access_token");
if (!json_valid(token))
{
json_object_put(response);
free(json_string);
return 0;
}
weechat_printf(
NULL,
_("%s%s: retrieved token: %s"),
weechat_prefix("network"), SLACK_PLUGIN_NAME,
json_object_get_string(token));
weechat_callback(strdup(json_object_get_string(token)));
}
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 token: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
json_object_get_string(error));
}
json_object_put(response);
free(json_string);
}
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:
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
client_wsi = NULL;
/* Does not doing this cause a leak?
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_oauth_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_oauth_hook_timer)
weechat_unhook(slack_oauth_hook_timer);
}
return WEECHAT_RC_OK;
}
void slack_oauth_request_token(char *code, void (*callback)(char *token))
{
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;
}
size_t urilen = snprintf(NULL, 0, endpoint, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, code) + 1;
uri = malloc(urilen);
snprintf(uri, urilen, endpoint, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, code);
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_oauth_hook_timer = weechat_hook_timer(1 * 1000, 0, 0,
&slack_oauth_timer_cb,
NULL, NULL);
weechat_callback = callback;
}

@ -1,10 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_OAUTH_H_
#define _SLACK_OAUTH_H_
extern void slack_oauth_request_token(char *code, void (*callback)(char *token));
#endif /*SLACK_OAUTH_H*/

@ -1,27 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#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;
request->idx = workspace->idx++;
return request;
}

@ -1,29 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_REQUEST_H_
#define _SLACK_REQUEST_H_
struct t_slack_request
{
struct t_slack_workspace *workspace;
int idx;
const void *pointer;
void *data;
char *uri;
struct lws *client_wsi;
struct lws_context *context;
struct t_json_chunk *json_chunks;
struct t_slack_request *prev_request;
struct t_slack_request *next_request;
};
struct t_slack_request *slack_request_alloc(
struct t_slack_workspace *workspace);
#endif /*SLACK_REQUEST_H*/

@ -1,348 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
client_wsi = NULL;
/* Does not doing this cause a leak?
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);
}

@ -1,20 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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,241 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
#include "slack-user.h"
#include "slack-channel.h"
const char *slack_user_get_colour(struct t_slack_user *user)
{
return weechat_info_get("nick_color", user->profile.display_name);
}
const char *slack_user_get_colour_for_nicklist(struct t_slack_user *user)
{
return weechat_info_get("nick_color_name", user->profile.display_name);
}
const char *slack_user_as_prefix(struct t_slack_workspace *workspace,
struct t_slack_user *user,
const char *name)
{
static char result[256];
(void) workspace;
snprintf(result, sizeof(result), "%s%s\t",
slack_user_get_colour(user),
name ? name : user->profile.display_name);
return result;
}
struct t_slack_user *slack_user_bot_search(struct t_slack_workspace *workspace,
const char *bot_id)
{
struct t_slack_user *ptr_user;
if (!workspace || !bot_id)
return NULL;
for (ptr_user = workspace->users; ptr_user;
ptr_user = ptr_user->next_user)
{
if (ptr_user->profile.bot_id &&
weechat_strcasecmp(ptr_user->profile.bot_id, bot_id) == 0)
return ptr_user;
}
return NULL;
}
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;
}
void slack_user_nicklist_add(struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
struct t_slack_user *user)
{
struct t_gui_nick_group *ptr_group;
struct t_gui_buffer *ptr_buffer;
ptr_buffer = channel ? channel->buffer : workspace->buffer;
ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL,
user->is_away ?
"+" : "...");
weechat_nicklist_add_nick(ptr_buffer, ptr_group,
user->profile.display_name,
user->is_away ?
"weechat.color.nicklist_away" :
slack_user_get_colour_for_nicklist(user),
user->is_away ? "+" : "",
"bar_fg",
1);
}
struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace,
const char *id, const char *display_name)
{
struct t_slack_user *new_user, *ptr_user;
if (!workspace || !id || !display_name)
{
return NULL;
}
if (!display_name[0] && strcmp("USLACKBOT", id) == 0)
return NULL;
if (!workspace->users)
slack_channel_add_nicklist_groups(workspace, NULL);
ptr_user = slack_user_search(workspace, id);
if (ptr_user)
{
slack_user_nicklist_add(workspace, NULL, ptr_user);
return ptr_user;
}
if ((new_user = malloc(sizeof(*new_user))) == NULL)
{
return NULL;
}
new_user->prev_user = workspace->last_user;
new_user->next_user = NULL;
if (workspace->last_user)
(workspace->last_user)->next_user = new_user;
else
workspace->users = new_user;
workspace->last_user = new_user;
new_user->id = strdup(id);
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 = display_name[0] ?
strdup(display_name) :
strdup("slackbot");
new_user->profile.real_name_normalized = NULL;
new_user->profile.email = NULL;
new_user->profile.team = NULL;
new_user->profile.bot_id = NULL;
new_user->updated = 0;
new_user->is_away = 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;
slack_user_nicklist_add(workspace, NULL, new_user);
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);
}

@ -1,74 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#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;
char *bot_id;
};
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_away;
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;
};
const char *slack_user_get_colour(struct t_slack_user *user);
const char *slack_user_as_prefix(struct t_slack_workspace *workspace,
struct t_slack_user *user,
const char *name);
struct t_slack_user *slack_user_bot_search(struct t_slack_workspace *workspace,
const char *bot_id);
struct t_slack_user *slack_user_search(struct t_slack_workspace *workspace,
const char *id);
struct t_slack_user *slack_user_new(struct t_slack_workspace *workspace,
const char *id, const char *display_name);
void slack_user_free_all(struct t_slack_workspace *workspace);
void slack_user_nicklist_add(struct t_slack_workspace *workspace,
struct t_slack_channel *channel,
struct t_slack_user *user);
#endif /*SLACK_USER_H*/

@ -1,972 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <libwebsockets.h>
#include <json.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-config.h"
#include "slack-input.h"
#include "slack-workspace.h"
#include "slack-api.h"
#include "slack-request.h"
#include "slack-user.h"
#include "slack-channel.h"
#include "slack-buffer.h"
struct t_slack_workspace *slack_workspaces = NULL;
struct t_slack_workspace *last_slack_workspace = NULL;
char *slack_workspace_options[SLACK_WORKSPACE_NUM_OPTIONS][2] =
{ { "token", "" },
};
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);
}
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
workspace->client_wsi = NULL;
/* Does not doing this cause a leak?
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;
if (!workspace_domain)
return NULL;
for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace)
{
if (strcmp(ptr_workspace->domain, workspace_domain) == 0)
return ptr_workspace;
}
/* workspace not found */
return NULL;
}
struct t_slack_workspace *slack_workspace_casesearch (const char *workspace_domain)
{
struct t_slack_workspace *ptr_workspace;
if (!workspace_domain)
return NULL;
for (ptr_workspace = slack_workspaces; ptr_workspace;
ptr_workspace = ptr_workspace->next_workspace)
{
if (weechat_strcasecmp (ptr_workspace->domain, workspace_domain) == 0)
return ptr_workspace;
}
/* workspace not found */
return NULL;
}
int slack_workspace_search_option(const char *option_name)
{
int i;
if (!option_name)
return -1;
for (i = 0; i < SLACK_WORKSPACE_NUM_OPTIONS; i++)
{
if (weechat_strcasecmp(slack_workspace_options[i][0], option_name) == 0)
return i;
}
/* workspace option not found */
return -1;
}
struct t_slack_workspace *slack_workspace_alloc(const char *domain)
{
struct t_slack_workspace *new_workspace;
int i, length;
char *option_name;
if (slack_workspace_casesearch(domain))
return NULL;
/* alloc memory for new workspace */
new_workspace = malloc(sizeof(*new_workspace));
if (!new_workspace)
{
weechat_printf(NULL,
_("%s%s: error when allocating new workspace"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
return NULL;
}
/* add new workspace to queue */
new_workspace->prev_workspace = last_slack_workspace;
new_workspace->next_workspace = NULL;
if (last_slack_workspace)
last_slack_workspace->next_workspace = new_workspace;
else
slack_workspaces = new_workspace;
last_slack_workspace = new_workspace;
/* set properties */
new_workspace->id = NULL;
new_workspace->name = NULL;
/* set name */
new_workspace->domain = strdup(domain);
/* internal vars */
new_workspace->reloading_from_config = 0;
new_workspace->reloaded_from_config = 0;
new_workspace->is_connected = 0;
new_workspace->disconnected = 0;
new_workspace->idx = 0;
new_workspace->uri = NULL;
new_workspace->ws_url = NULL;
new_workspace->client_wsi = NULL;
new_workspace->context = NULL;
new_workspace->json_chunks = NULL;
new_workspace->requests = NULL;
new_workspace->last_request = NULL;
new_workspace->user = NULL;
new_workspace->nick = NULL;
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;
new_workspace->emoji = NULL;
new_workspace->last_emoji = NULL;
/* create options with null value */
for (i = 0; i < SLACK_WORKSPACE_NUM_OPTIONS; i++)
{
length = strlen(new_workspace->domain) + 1 +
strlen(slack_workspace_options[i][0]) +
512 + /* inherited option name(slack.workspace_default.xxx) */
1;
option_name = malloc(length);
if (option_name)
{
snprintf(option_name, length, "%s.%s << slack.workspace_default.%s",
new_workspace->domain,
slack_workspace_options[i][0],
slack_workspace_options[i][0]);
new_workspace->options[i] = slack_config_workspace_new_option(
slack_config_file,
slack_config_section_workspace,
i,
option_name,
NULL,
NULL,
1,
&slack_config_workspace_check_value_cb,
slack_workspace_options[i][0],
NULL,
&slack_config_workspace_change_cb,
slack_workspace_options[i][0],
NULL);
slack_config_workspace_change_cb(slack_workspace_options[i][0], NULL,
new_workspace->options[i]);
free(option_name);
}
}
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);
slack_user_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->context)
lws_context_destroy(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;
}
while (workspace->requests)
{
struct t_slack_request *request_ptr = workspace->requests->next_request;
workspace->requests->client_wsi = NULL;
if (workspace->requests->context)
{
lws_context_destroy(workspace->requests->context);
workspace->requests->context = NULL;
if (workspace->requests->uri)
{
free(workspace->requests->uri);
workspace->requests->uri = NULL;
}
}
free(workspace->requests);
workspace->requests = request_ptr;
}
if (workspace->user)
free(workspace->user);
if (workspace->nick)
free(workspace->nick);
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)
{
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 reconnect)
{
(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
*/
slack_user_free_all(workspace);
weechat_nicklist_remove_all(workspace->buffer);
for (ptr_channel = workspace->channels; ptr_channel;
ptr_channel = ptr_channel->next_channel)
{
weechat_nicklist_remove_all(ptr_channel->buffer);
weechat_printf(
ptr_channel->buffer,
_("%s%s: disconnected from workspace"),
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);
}
}
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),
"workspace.%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),
"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;
}
void slack_workspace_close_connection(struct t_slack_workspace *workspace)
{
struct t_slack_request *ptr_request;
workspace->is_connected = 0;
workspace->client_wsi = NULL;
workspace->context = NULL;
for (ptr_request = workspace->requests; ptr_request;
ptr_request = ptr_request->next_request)
{
if (ptr_request->context)
{
struct t_slack_request *new_requests;
lws_context_destroy(ptr_request->context);
ptr_request->context = NULL;
if (ptr_request->uri)
{
free(ptr_request->uri);
ptr_request->uri = NULL;
}
/* remove request from requests list */
if (workspace->last_request == ptr_request)
workspace->last_request = ptr_request->prev_request;
if (ptr_request->prev_request)
{
(ptr_request->prev_request)->next_request = ptr_request->next_request;
new_requests = workspace->requests;
}
else
new_requests = ptr_request->next_request;
if (ptr_request->next_request)
(ptr_request->next_request)->prev_request = ptr_request->prev_request;
workspace->requests = new_requests;
}
}
}
void slack_workspace_websocket_create(struct t_slack_workspace *workspace)
{
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;
struct t_slack_request *ptr_request;
(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;
for (ptr_request = ptr_workspace->requests; ptr_request;
ptr_request = ptr_request->next_request)
{
if (ptr_request->client_wsi)
{
lws_service(ptr_request->context, 0);
}
else if (ptr_request->context)
{
struct t_slack_request *new_requests;
lws_context_destroy(ptr_request->context);
ptr_request->context = NULL;
if (ptr_request->uri)
{
free(ptr_request->uri);
ptr_request->uri = NULL;
}
ptr_request->pointer = NULL;
if (ptr_request->data)
{
free(ptr_request->data);
ptr_request->data = NULL;
}
/* remove request from requests list */
if (ptr_workspace->last_request == ptr_request)
ptr_workspace->last_request = ptr_request->prev_request;
if (ptr_request->prev_request)
{
(ptr_request->prev_request)->next_request = ptr_request->next_request;
new_requests = ptr_workspace->requests;
}
else
new_requests = ptr_request->next_request;
if (ptr_request->next_request)
(ptr_request->next_request)->prev_request = ptr_request->prev_request;
ptr_workspace->requests = new_requests;
}
}
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;
}
void slack_workspace_register_request(struct t_slack_workspace *workspace,
struct t_slack_request *request)
{
request->prev_request = workspace->last_request;
request->next_request = NULL;
if (workspace->last_request)
(workspace->last_request)->next_request = request;
else
workspace->requests = request;
workspace->last_request = request;
}
struct t_slack_workspace_emoji *slack_workspace_emoji_search(
struct t_slack_workspace *workspace,
const char *name)
{
struct t_slack_workspace_emoji *ptr_emoji;
if (!workspace || !name)
return NULL;
for (ptr_emoji = workspace->emoji; ptr_emoji;
ptr_emoji = ptr_emoji->next_emoji)
{
if (weechat_strcasecmp(ptr_emoji->name, name) == 0)
return ptr_emoji;
}
return NULL;
}
struct t_slack_workspace_emoji *slack_workspace_add_emoji(
struct t_slack_workspace *workspace,
const char *name, const char *url)
{
struct t_slack_workspace_emoji *ptr_emoji, *new_emoji;
char shortname[SLACK_WORKSPACE_EMOJI_SHORTNAME_MAX_LEN + 1];
(void) url;
if (!workspace || !name || !name[0])
return NULL;
snprintf(shortname, SLACK_WORKSPACE_EMOJI_SHORTNAME_MAX_LEN + 1,
":%s:", name);
ptr_emoji = slack_workspace_emoji_search(workspace, shortname);
if (ptr_emoji)
{
return ptr_emoji;
}
if ((new_emoji = malloc(sizeof(*new_emoji))) == NULL)
return NULL;
new_emoji->name = strdup(shortname);
new_emoji->url = strdup(url);
new_emoji->prev_emoji = workspace->last_emoji;
new_emoji->next_emoji = NULL;
if (workspace->last_emoji)
(workspace->last_emoji)->next_emoji = new_emoji;
else
workspace->emoji = new_emoji;
workspace->last_emoji = new_emoji;
return new_emoji;
}

@ -1,95 +0,0 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#ifndef _SLACK_WORKSPACE_H_
#define _SLACK_WORKSPACE_H_
#define SLACK_WORKSPACE_EMOJI_SHORTNAME_MAX_LEN 1 + 100 + 1
extern struct t_slack_workspace *slack_workspaces;
extern struct t_slack_workspace *last_slack_workspace;
struct t_slack_workspace_emoji
{
char *name;
char *url;
struct t_slack_workspace_emoji *prev_emoji;
struct t_slack_workspace_emoji *next_emoji;
};
enum t_slack_workspace_option
{
SLACK_WORKSPACE_OPTION_TOKEN,
SLACK_WORKSPACE_NUM_OPTIONS,
};
struct t_json_chunk
{
char *data;
struct t_json_chunk *next;
};
struct t_slack_workspace
{
char *id;
char *name;
char *domain;
struct t_config_option *options[SLACK_WORKSPACE_NUM_OPTIONS];
int reloading_from_config;
int reloaded_from_config;
int is_connected;
int disconnected;
int idx;
char *uri;
char *ws_url;
struct lws *client_wsi;
struct lws_context *context;
struct t_json_chunk *json_chunks;
struct t_slack_request *requests;
struct t_slack_request *last_request;
char *user;
char *nick;
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_emoji *emoji;
struct t_slack_workspace_emoji *last_emoji;
struct t_slack_workspace *prev_workspace;
struct t_slack_workspace *next_workspace;
};
extern char *slack_workspace_options[][2];
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);
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 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);
void slack_workspace_register_request(struct t_slack_workspace *workspace,
struct t_slack_request *request);
struct t_slack_workspace_emoji *slack_workspace_emoji_search(
struct t_slack_workspace *workspace,
const char *name);
struct t_slack_workspace_emoji *slack_workspace_add_emoji(
struct t_slack_workspace *workspace,
const char *name, const char *url);
#endif /*SLACK_WORKSPACE_H*/
Loading…
Cancel
Save