weechat-xmpp/slack-channel.c

643 lines
20 KiB
C
Raw Normal View History

2018-05-09 04:39:16 +00:00
// 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/.
2018-05-02 07:11:57 +00:00
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
2018-05-06 00:09:58 +00:00
#include <time.h>
2018-05-02 07:11:57 +00:00
#include "weechat-plugin.h"
#include "slack.h"
#include "slack-workspace.h"
2018-05-06 00:09:58 +00:00
#include "slack-user.h"
2018-05-02 07:11:57 +00:00
#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;
2018-05-06 00:09:58 +00:00
int buffer_created;
2018-05-02 07:11:57 +00:00
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;
}
2018-05-02 15:55:41 +00:00
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);
}
2018-05-02 07:11:57 +00:00
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;
2018-05-06 00:09:58 +00:00
struct t_hook *typing_timer;
2018-05-02 22:16:20 +00:00
char buffer_name[SLACK_CHANNEL_NAME_MAX_LEN + 2];
2018-05-02 07:11:57 +00:00
2018-05-02 15:55:41 +00:00
if (!workspace || !id || !name || !name[0])
2018-05-02 07:11:57 +00:00
return NULL;
ptr_channel = slack_channel_search(workspace, id);
if (ptr_channel)
{
return ptr_channel;
}
2018-05-02 22:16:20 +00:00
buffer_name[0] = '#';
strncpy(&buffer_name[1], name, SLACK_CHANNEL_NAME_MAX_LEN + 1);
ptr_buffer = slack_channel_create_buffer(workspace, type, buffer_name);
2018-05-02 07:11:57 +00:00
if (!ptr_buffer)
return NULL;
if ((new_channel = malloc(sizeof(*new_channel))) == NULL)
return NULL;
2018-05-06 00:09:58 +00:00
typing_timer = weechat_hook_timer(1 * 1000, 0, 0,
&slack_channel_typing_cb,
new_channel, NULL);
2018-05-02 07:11:57 +00:00
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;
2018-05-06 00:09:58 +00:00
new_channel->typing_hook_timer = typing_timer;
new_channel->members_speaking[0] = NULL;
new_channel->members_speaking[1] = NULL;
2018-05-06 00:09:58 +00:00
new_channel->typings = NULL;
new_channel->last_typing = NULL;
2018-05-02 07:11:57 +00:00
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;
2018-05-02 15:55:41 +00:00
new_channel->next_channel = NULL;
2018-05-02 07:11:57 +00:00
if (workspace->last_channel)
(workspace->last_channel)->next_channel = new_channel;
2018-05-02 15:55:41 +00:00
else
workspace->channels = new_channel;
2018-05-02 07:11:57 +00:00
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);
}
}
}
}
2018-05-06 00:09:58 +00:00
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;
2018-05-06 14:02:15 +00:00
const char *localvar;
2018-05-06 00:09:58 +00:00
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++;
}
2018-05-06 14:02:15 +00:00
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");
2018-05-06 00:09:58 +00:00
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);
}
2018-05-02 07:11:57 +00:00
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;
2018-05-06 00:09:58 +00:00
/* remove member from members list */
2018-05-02 07:11:57 +00:00
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;
2018-05-06 00:09:58 +00:00
/* remove channel from channels list */
2018-05-02 07:11:57 +00:00
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;
2018-05-06 00:09:58 +00:00
/* free hooks */
if (channel->typing_hook_timer)
weechat_unhook(channel->typing_hook_timer);
2018-05-02 07:11:57 +00:00
/* free linked lists */
2018-05-06 00:09:58 +00:00
slack_channel_typing_free_all(channel);
2018-05-02 07:11:57 +00:00
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);
2018-05-06 00:09:58 +00:00
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);
2018-05-02 07:11:57 +00:00
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]);
2018-05-02 07:11:57 +00:00
if (channel->buffer_as_string)
2018-05-06 00:09:58 +00:00
free(channel->buffer_as_string);
2018-05-02 07:11:57 +00:00
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);
}
2018-05-06 14:02:15 +00:00
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;
}
2018-05-07 17:08:34 +00:00
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;
}