typing notifications

v1
Tony Olagbaiye 7 years ago
parent 22f22a0aee
commit 0c575b9dbc

1
.gitignore vendored

@ -1,4 +1,5 @@
# Prerequisites # Prerequisites
compile_commands.json
cscope* cscope*
.depend .depend
*.d *.d

@ -1,8 +1,10 @@
CC=clang CC=clang
CXX=clang++ CXX=g++
RM=rm -f RM=rm -f
CFLAGS=-fsanitize=address -fno-omit-frame-pointer -fPIC -std=gnu99 -g -Wall -Wextra -Werror-implicit-function-declaration -Wno-missing-field-initializers -I libwebsockets/include -I json-c SANCFLAGS=-fsanitize=address -fsanitize=leak
LDFLAGS=-shared -g -fsanitize=address SANLDFLAGS=-static-libasan -static-liblsan
CFLAGS=$(SANCFLAGS) -fno-omit-frame-pointer -fPIC -std=gnu99 -g -Wall -Wextra -Werror-implicit-function-declaration -Wno-missing-field-initializers -I libwebsockets/include -I json-c
LDFLAGS=-shared -g $(SANCFLAGS) $(SANLDFLAGS)
LDLIBS=-lgnutls LDLIBS=-lgnutls
SRCS=slack.c \ SRCS=slack.c \
@ -21,6 +23,7 @@ SRCS=slack.c \
api/slack-api-hello.c \ api/slack-api-hello.c \
api/slack-api-error.c \ api/slack-api-error.c \
api/slack-api-message.c \ api/slack-api-message.c \
api/slack-api-user-typing.c \
api/message/slack-api-message-unimplemented.c \ api/message/slack-api-message-unimplemented.c \
request/slack-request-chat-postmessage.c \ request/slack-request-chat-postmessage.c \
request/slack-request-channels-list.c \ request/slack-request-channels-list.c \
@ -30,7 +33,7 @@ OBJS=$(subst .c,.o,$(SRCS)) libwebsockets/lib/libwebsockets.a json-c/libjson-c.a
all: libwebsockets/lib/libwebsockets.a json-c/libjson-c.a weechat-slack all: libwebsockets/lib/libwebsockets.a json-c/libjson-c.a weechat-slack
weechat-slack: $(OBJS) weechat-slack: $(OBJS)
$(CC) $(LDFLAGS) -o slack.so $(OBJS) $(LDLIBS) $(CXX) $(LDFLAGS) -o slack.so $(OBJS) $(LDLIBS)
libwebsockets/lib/libwebsockets.a: libwebsockets/lib/libwebsockets.a:
cd libwebsockets && cmake -DLWS_STATIC_PIC=ON -DLWS_WITH_SHARED=OFF -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITH_LIBEV=OFF -DLWS_WITH_LIBUV=OFF -DLWS_WITH_LIBEVENT=OFF -DCMAKE_BUILD_TYPE=DEBUG . cd libwebsockets && cmake -DLWS_STATIC_PIC=ON -DLWS_WITH_SHARED=OFF -DLWS_WITHOUT_TESTAPPS=ON -DLWS_WITH_LIBEV=OFF -DLWS_WITH_LIBUV=OFF -DLWS_WITH_LIBEVENT=OFF -DCMAKE_BUILD_TYPE=DEBUG .

@ -82,6 +82,7 @@ int slack_api_message_message_handle(struct t_slack_workspace *workspace,
{ {
struct t_slack_channel *ptr_channel; struct t_slack_channel *ptr_channel;
struct t_slack_user *ptr_user; struct t_slack_user *ptr_user;
struct t_slack_channel_typing *ptr_typing;
ptr_channel = slack_channel_search(workspace, channel); ptr_channel = slack_channel_search(workspace, channel);
if (!ptr_channel) if (!ptr_channel)
@ -100,6 +101,14 @@ int slack_api_message_message_handle(struct t_slack_workspace *workspace,
message); message);
free(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; return 1;
} }

@ -0,0 +1,63 @@
#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));
}

@ -0,0 +1,7 @@
#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*/

@ -245,6 +245,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
json_object_put(response); json_object_put(response);
free(json_string); free(json_string);
} }
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL; request->client_wsi = NULL;
/* Does not doing this cause a leak? /* Does not doing this cause a leak?

@ -165,6 +165,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
json_object_put(response); json_object_put(response);
free(json_string); free(json_string);
} }
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL; request->client_wsi = NULL;
/* Does not doing this cause a leak? /* Does not doing this cause a leak?

@ -251,6 +251,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
json_object_put(response); json_object_put(response);
free(json_string); free(json_string);
} }
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
request->client_wsi = NULL; request->client_wsi = NULL;
/* Does not doing this cause a leak? /* Does not doing this cause a leak?

@ -10,6 +10,7 @@
#include "api/slack-api-hello.h" #include "api/slack-api-hello.h"
#include "api/slack-api-error.h" #include "api/slack-api-error.h"
#include "api/slack-api-message.h" #include "api/slack-api-message.h"
#include "api/slack-api-user-typing.h"
struct stringcase struct stringcase
{ {
@ -22,6 +23,7 @@ static struct stringcase cases[] =
{ { "hello", &slack_api_hello } { { "hello", &slack_api_hello }
, { "error", &slack_api_error } , { "error", &slack_api_error }
, { "message", &slack_api_message } , { "message", &slack_api_message }
, { "user_typing", &slack_api_user_typing }
}; };
static int stringcase_cmp(const void *p1, const void *p2) static int stringcase_cmp(const void *p1, const void *p2)
@ -71,49 +73,95 @@ static int callback_ws(struct lws* wsi, enum lws_callback_reasons reason,
weechat_prefix("network"), SLACK_PLUGIN_NAME, weechat_prefix("network"), SLACK_PLUGIN_NAME,
(const char *)in); (const char *)in);
{ {
int data_size;
char *json_string; char *json_string;
json_object *response, *type; json_object *response, *type;
struct t_json_chunk *new_chunk, *last_chunk, *chunk_ptr;
json_string = strdup((const char *)in); new_chunk = malloc(sizeof(*new_chunk));
new_chunk->data = malloc(((int)len) + 1);
new_chunk->data[0] = '\0';
new_chunk->next = NULL;
response = json_tokener_parse(json_string); strncat(new_chunk->data, in, (int)len);
type = json_object_object_get(response, "type");
if (!type) if (workspace->json_chunks)
{
for (last_chunk = workspace->json_chunks; last_chunk->next;
last_chunk = last_chunk->next);
last_chunk->next = new_chunk;
}
else
{ {
weechat_printf( workspace->json_chunks = new_chunk;
workspace->buffer, }
_("%s%s: unexpected data received from websocket: closing"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
slack_workspace_disconnect(workspace, 0); data_size = 0;
for (chunk_ptr = workspace->json_chunks; chunk_ptr; chunk_ptr = chunk_ptr->next)
{
data_size += strlen(chunk_ptr->data);
}
json_object_put(response); json_string = malloc(data_size + 1);
free(json_string); json_string[0] = '\0';
return -1;
for (chunk_ptr = workspace->json_chunks; chunk_ptr; chunk_ptr = chunk_ptr->next)
{
strcat(json_string, chunk_ptr->data);
} }
if (!slack_api_route_message(workspace, response = json_tokener_parse(json_string);
json_object_get_string(type), response)) if (response)
{ {
weechat_printf( for (chunk_ptr = workspace->json_chunks; chunk_ptr; workspace->json_chunks = chunk_ptr)
workspace->buffer, {
_("%s%s: error while handling message: %s"), chunk_ptr = chunk_ptr->next;
weechat_prefix("error"), SLACK_PLUGIN_NAME, free(workspace->json_chunks->data);
json_string); free(workspace->json_chunks);
weechat_printf( }
workspace->buffer,
_("%s%s: closing connection."), type = json_object_object_get(response, "type");
weechat_prefix("error"), SLACK_PLUGIN_NAME); if (!type)
{
slack_workspace_disconnect(workspace, 0); weechat_printf(
workspace->buffer,
_("%s%s: unexpected data received from websocket: closing"),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
slack_workspace_disconnect(workspace, 0);
json_object_put(response);
free(json_string);
return -1;
}
if (!slack_api_route_message(workspace,
json_object_get_string(type), response))
{
weechat_printf(
workspace->buffer,
_("%s%s: error while handling message: %s"),
weechat_prefix("error"), SLACK_PLUGIN_NAME,
json_string);
weechat_printf(
workspace->buffer,
_("%s%s: closing connection."),
weechat_prefix("error"), SLACK_PLUGIN_NAME);
slack_workspace_disconnect(workspace, 0);
json_object_put(response);
free(json_string);
return -1;
}
json_object_put(response); json_object_put(response);
free(json_string); free(json_string);
return -1;
} }
else
json_object_put(response); {
free(json_string); free(json_string);
}
} }
return 0; /* don't passthru */ return 0; /* don't passthru */

@ -1,3 +1,5 @@
#include <string.h>
#include "weechat-plugin.h" #include "weechat-plugin.h"
#include "slack.h" #include "slack.h"
#include "slack-workspace.h" #include "slack-workspace.h"
@ -42,6 +44,67 @@ void slack_buffer_get_workspace_and_channel(struct t_gui_buffer *buffer,
/* no workspace or channel found */ /* 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, int slack_buffer_nickcmp_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer, struct t_gui_buffer *buffer,
const char *nick1, const char *nick1,

@ -5,6 +5,13 @@ void slack_buffer_get_workspace_and_channel(struct t_gui_buffer *buffer,
struct t_slack_workspace **workspace, struct t_slack_workspace **workspace,
struct t_slack_channel **channel); 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, int slack_buffer_nickcmp_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer, struct t_gui_buffer *buffer,
const char *nick1, const char *nick1,

@ -1,10 +1,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "weechat-plugin.h" #include "weechat-plugin.h"
#include "slack.h" #include "slack.h"
#include "slack-workspace.h" #include "slack-workspace.h"
#include "slack-user.h"
#include "slack-channel.h" #include "slack-channel.h"
#include "slack-input.h" #include "slack-input.h"
#include "slack-buffer.h" #include "slack-buffer.h"
@ -73,7 +75,7 @@ struct t_gui_buffer *slack_channel_create_buffer(struct t_slack_workspace *works
const char *name) const char *name)
{ {
struct t_gui_buffer *ptr_buffer; struct t_gui_buffer *ptr_buffer;
int buffer_created, current_buffer_number; int buffer_created;
const char *short_name, *localvar_channel; const char *short_name, *localvar_channel;
char buffer_name[256]; char buffer_name[256];
@ -89,9 +91,6 @@ struct t_gui_buffer *slack_channel_create_buffer(struct t_slack_workspace *works
} }
else else
{ {
current_buffer_number = weechat_buffer_get_integer(
weechat_current_buffer(), "number");
ptr_buffer = weechat_buffer_new(buffer_name, ptr_buffer = weechat_buffer_new(buffer_name,
&slack_input_data_cb, NULL, NULL, &slack_input_data_cb, NULL, NULL,
&slack_buffer_close_cb, NULL, NULL); &slack_buffer_close_cb, NULL, NULL);
@ -181,6 +180,7 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
{ {
struct t_slack_channel *new_channel, *ptr_channel; struct t_slack_channel *new_channel, *ptr_channel;
struct t_gui_buffer *ptr_buffer; struct t_gui_buffer *ptr_buffer;
struct t_hook *typing_timer;
char buffer_name[SLACK_CHANNEL_NAME_MAX_LEN + 2]; char buffer_name[SLACK_CHANNEL_NAME_MAX_LEN + 2];
if (!workspace || !id || !name || !name[0]) if (!workspace || !id || !name || !name[0])
@ -202,6 +202,10 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
if ((new_channel = malloc(sizeof(*new_channel))) == NULL) if ((new_channel = malloc(sizeof(*new_channel))) == NULL)
return 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->type = type;
new_channel->id = strdup(id); new_channel->id = strdup(id);
new_channel->name = strdup(name); new_channel->name = strdup(name);
@ -228,6 +232,9 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
new_channel->is_user_deleted = 0; new_channel->is_user_deleted = 0;
new_channel->typing_hook_timer = typing_timer;
new_channel->typings = NULL;
new_channel->last_typing = NULL;
new_channel->members = NULL; new_channel->members = NULL;
new_channel->last_member = NULL; new_channel->last_member = NULL;
new_channel->buffer = ptr_buffer; new_channel->buffer = ptr_buffer;
@ -244,6 +251,137 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
return new_channel; return new_channel;
} }
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;
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++;
}
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, void slack_channel_member_free(struct t_slack_channel *channel,
struct t_slack_channel_member *member) struct t_slack_channel_member *member)
{ {
@ -252,7 +390,7 @@ void slack_channel_member_free(struct t_slack_channel *channel,
if (!channel || !member) if (!channel || !member)
return; return;
/* remove member from members list */ /* remove member from members list */
if (channel->last_member == member) if (channel->last_member == member)
channel->last_member = member->prev_member; channel->last_member = member->prev_member;
if (member->prev_member) if (member->prev_member)
@ -289,7 +427,7 @@ void slack_channel_free(struct t_slack_workspace *workspace,
if (!workspace || !channel) if (!workspace || !channel)
return; return;
/* remove channel from channels list */ /* remove channel from channels list */
if (workspace->last_channel == channel) if (workspace->last_channel == channel)
workspace->last_channel = channel->prev_channel; workspace->last_channel = channel->prev_channel;
if (channel->prev_channel) if (channel->prev_channel)
@ -303,7 +441,12 @@ void slack_channel_free(struct t_slack_workspace *workspace,
if (channel->next_channel) if (channel->next_channel)
(channel->next_channel)->prev_channel = channel->prev_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 */ /* free linked lists */
slack_channel_typing_free_all(channel);
slack_channel_member_free_all(channel); slack_channel_member_free_all(channel);
/* free channel data */ /* free channel data */
@ -313,18 +456,18 @@ void slack_channel_free(struct t_slack_workspace *workspace,
free(channel->name); free(channel->name);
if (channel->name_normalized) if (channel->name_normalized)
free(channel->name_normalized); free(channel->name_normalized);
if (channel->topic.value) if (channel->topic.value)
free(channel->topic.value); free(channel->topic.value);
if (channel->topic.creator) if (channel->topic.creator)
free(channel->topic.creator); free(channel->topic.creator);
if (channel->purpose.value) if (channel->purpose.value)
free(channel->purpose.value); free(channel->purpose.value);
if (channel->purpose.creator) if (channel->purpose.creator)
free(channel->purpose.creator); free(channel->purpose.creator);
if (channel->creator) if (channel->creator)
free(channel->creator); free(channel->creator);
if (channel->buffer_as_string) if (channel->buffer_as_string)
free (channel->buffer_as_string); free(channel->buffer_as_string);
free(channel); free(channel);

@ -11,6 +11,16 @@ enum t_slack_channel_type
SLACK_CHANNEL_TYPE_IM, 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 struct t_slack_channel_member
{ {
char *id; char *id;
@ -61,6 +71,9 @@ struct t_slack_channel
/* im */ /* im */
int is_user_deleted; int is_user_deleted;
struct t_hook *typing_hook_timer;
struct t_slack_channel_typing *typings;
struct t_slack_channel_typing *last_typing;
struct t_slack_channel_member *members; struct t_slack_channel_member *members;
struct t_slack_channel_member *last_member; struct t_slack_channel_member *last_member;
struct t_gui_buffer *buffer; struct t_gui_buffer *buffer;
@ -80,6 +93,22 @@ struct t_slack_channel *slack_channel_new(struct t_slack_workspace *workspace,
enum t_slack_channel_type type, enum t_slack_channel_type type,
const char *id, const char *name); const char *id, const char *name);
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_free_all(struct t_slack_workspace *workspace);
#endif /*SLACK_CHANNEL_H*/ #endif /*SLACK_CHANNEL_H*/

@ -1,5 +1,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <regex.h> #include <regex.h>
#include "../weechat-plugin.h" #include "../weechat-plugin.h"
@ -9,7 +10,7 @@
#include "../slack-user.h" #include "../slack-user.h"
#include "../slack-message.h" #include "../slack-message.h"
static const char format_regex[] = "<(.*?)>"; static const char format_regex[] = "<([^>]*?)>";
static const size_t max_groups = 2; static const size_t max_groups = 2;
char *slack_message_translate_code(struct t_slack_workspace *workspace, char *slack_message_translate_code(struct t_slack_workspace *workspace,
@ -30,7 +31,12 @@ char *slack_message_translate_code(struct t_slack_workspace *workspace,
case '@': /* user */ case '@': /* user */
user = slack_user_search(workspace, code+1); user = slack_user_search(workspace, code+1);
if (user) if (user)
return strdup(user->profile.display_name); {
size_t nicklen = snprintf(NULL, 0, "%s@%s%s", weechat_color("chat_nick"), user->profile.display_name, weechat_color("reset")) + 1;
char *tag = malloc(nicklen);
snprintf(tag, nicklen, "%s@%s%s", weechat_color("chat_nick"), user->profile.display_name, weechat_color("reset"));
return tag;
}
else else
return strdup(code); return strdup(code);
case '!': /* special */ case '!': /* special */
@ -49,7 +55,7 @@ char *slack_message_decode(struct t_slack_workspace *workspace,
regex_t reg; regex_t reg;
regmatch_t groups[max_groups]; regmatch_t groups[max_groups];
char msgbuf[100]; char msgbuf[100];
char *decoded_text, *pos; char *decoded_text;
const char *cursor; const char *cursor;
size_t offset; size_t offset;
@ -74,8 +80,7 @@ char *slack_message_decode(struct t_slack_workspace *workspace,
weechat_prefix("error"), SLACK_PLUGIN_NAME); weechat_prefix("error"), SLACK_PLUGIN_NAME);
return strdup(text); return strdup(text);
} }
pos = decoded_text; decoded_text[0] = '\0';
pos[0] = '\0';
for (cursor = text; regexec(&reg, cursor, max_groups, groups, 0) == 0; cursor += offset) for (cursor = text; regexec(&reg, cursor, max_groups, groups, 0) == 0; cursor += offset)
{ {
@ -85,6 +90,7 @@ char *slack_message_decode(struct t_slack_workspace *workspace,
if (!copy) if (!copy)
{ {
regfree(&reg); regfree(&reg);
free(decoded_text);
weechat_printf( weechat_printf(
workspace->buffer, workspace->buffer,
_("%s%s: error allocating space for message"), _("%s%s: error allocating space for message"),
@ -98,6 +104,7 @@ char *slack_message_decode(struct t_slack_workspace *workspace,
{ {
free(copy); free(copy);
regfree(&reg); regfree(&reg);
free(decoded_text);
weechat_printf( weechat_printf(
workspace->buffer, workspace->buffer,
_("%s%s: error allocating space for message"), _("%s%s: error allocating space for message"),
@ -112,6 +119,7 @@ char *slack_message_decode(struct t_slack_workspace *workspace,
free(match); free(match);
free(copy); free(copy);
regfree(&reg); regfree(&reg);
free(decoded_text);
weechat_printf( weechat_printf(
workspace->buffer, workspace->buffer,
_("%s%s: error allocating space for message"), _("%s%s: error allocating space for message"),
@ -120,18 +128,18 @@ char *slack_message_decode(struct t_slack_workspace *workspace,
} }
free(copy); free(copy);
pos = strncat(decoded_text, prematch, strncat(decoded_text, prematch,
SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1); SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
free(prematch); free(prematch);
char *replacement = slack_message_translate_code(workspace, match); char *replacement = slack_message_translate_code(workspace, match);
free(match); free(match);
pos = strncat(decoded_text, replacement, strncat(decoded_text, replacement,
SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1); SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
free(replacement); free(replacement);
} }
pos = strncat(decoded_text, cursor, strncat(decoded_text, cursor,
SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1); SLACK_MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
regfree(&reg); regfree(&reg);

@ -228,6 +228,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
json_object_put(response); json_object_put(response);
free(json_string); free(json_string);
} }
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
client_wsi = NULL; client_wsi = NULL;
/* Does not doing this cause a leak? /* Does not doing this cause a leak?

@ -142,7 +142,7 @@ void slack_user_free(struct t_slack_workspace *workspace,
if (!workspace || !user) if (!workspace || !user)
return; return;
/* remove user from users list */ /* remove user from users list */
if (workspace->last_user == user) if (workspace->last_user == user)
workspace->last_user = user->prev_user; workspace->last_user = user->prev_user;
if (user->prev_user) if (user->prev_user)
@ -173,22 +173,22 @@ void slack_user_free(struct t_slack_workspace *workspace,
free(user->tz_label); free(user->tz_label);
if (user->locale) if (user->locale)
free(user->locale); free(user->locale);
if (user->profile.avatar_hash) if (user->profile.avatar_hash)
free(user->profile.avatar_hash); free(user->profile.avatar_hash);
if (user->profile.status_text) if (user->profile.status_text)
free(user->profile.status_text); free(user->profile.status_text);
if (user->profile.status_emoji) if (user->profile.status_emoji)
free(user->profile.status_emoji); free(user->profile.status_emoji);
if (user->profile.real_name) if (user->profile.real_name)
free(user->profile.real_name); free(user->profile.real_name);
if (user->profile.display_name) if (user->profile.display_name)
free(user->profile.display_name); free(user->profile.display_name);
if (user->profile.real_name_normalized) if (user->profile.real_name_normalized)
free(user->profile.real_name_normalized); free(user->profile.real_name_normalized);
if (user->profile.email) if (user->profile.email)
free(user->profile.email); free(user->profile.email);
if (user->profile.team) if (user->profile.team)
free(user->profile.team); free(user->profile.team);
free(user); free(user);

@ -247,6 +247,7 @@ static int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
json_object_put(response); json_object_put(response);
free(json_string); free(json_string);
} }
/* fallthrough */
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
workspace->client_wsi = NULL; workspace->client_wsi = NULL;
/* Does not doing this cause a leak? /* Does not doing this cause a leak?

@ -6,7 +6,7 @@ extern struct t_slack_workspace *last_slack_workspace;
enum t_slack_workspace_option enum t_slack_workspace_option
{ {
SLACK_WORKSPACE_OPTION_TOKEN = 0, SLACK_WORKSPACE_OPTION_TOKEN,
SLACK_WORKSPACE_NUM_OPTIONS, SLACK_WORKSPACE_NUM_OPTIONS,
}; };

@ -10,6 +10,7 @@
#include "slack-command.h" #include "slack-command.h"
#include "slack-workspace.h" #include "slack-workspace.h"
#include "slack-api.h" #include "slack-api.h"
#include "slack-buffer.h"
WEECHAT_PLUGIN_NAME(SLACK_PLUGIN_NAME); WEECHAT_PLUGIN_NAME(SLACK_PLUGIN_NAME);
@ -23,6 +24,8 @@ struct t_weechat_plugin *weechat_slack_plugin = NULL;
struct t_hook *slack_hook_timer = NULL; struct t_hook *slack_hook_timer = NULL;
struct t_gui_bar_item *slack_typing_bar_item = NULL;
void slack_lwsl_emit_weechat(int level, const char *line) void slack_lwsl_emit_weechat(int level, const char *line)
{ {
char buf[50]; char buf[50];
@ -60,6 +63,18 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
&slack_workspace_timer_cb, &slack_workspace_timer_cb,
NULL, NULL); NULL, NULL);
if (!weechat_bar_search("typing"))
{
weechat_bar_new("typing", "off", "400", "window", "${typing}",
"bottom", "horizontal", "vertical",
"1", "1", "default", "default", "default",
"off", "slack_typing");
}
slack_typing_bar_item = weechat_bar_item_new("slack_typing",
&slack_buffer_typing_bar_cb,
NULL, NULL);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
@ -68,6 +83,9 @@ int weechat_plugin_end(struct t_weechat_plugin *plugin)
/* make C compiler happy */ /* make C compiler happy */
(void) plugin; (void) plugin;
if (slack_typing_bar_item)
weechat_bar_item_remove(slack_typing_bar_item);
if (slack_hook_timer) if (slack_hook_timer)
weechat_unhook(slack_hook_timer); weechat_unhook(slack_hook_timer);

Loading…
Cancel
Save