buffers! hooray.

v1
Tony Olagbaiye 4 years ago
parent b6b6ed6246
commit 2b42e8cd2a
No known key found for this signature in database
GPG Key ID: 9E2FF3BDEBDFC910

@ -18,12 +18,6 @@ export_function()
use_guix() use_guix()
{ {
# Set GitHub token.
export GUIX_GITHUB_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Unset 'GUIX_PACKAGE_PATH'.
export GUIX_PACKAGE_PATH=""
# Recreate a garbage collector root. # Recreate a garbage collector root.
gcroots="$HOME/.config/guix/gcroots" gcroots="$HOME/.config/guix/gcroots"
mkdir -p "$gcroots" mkdir -p "$gcroots"
@ -51,4 +45,4 @@ use_guix()
export CC=gcc export CC=gcc
} }
use guix use guix --with-debug-info=weechat --with-debug-info=libstrophe

@ -1,12 +1,12 @@
ifdef DEBUG ifdef DEBUG
DBGCFLAGS=-fsanitize=address -fsanitize=leak -fsanitize=undefined DBGCFLAGS=-fsanitize=address -fsanitize=undefined -fsanitize=leak
DBGLDFLAGS=-static-libasan -static-liblsan -static-libubsan DBGLDFLAGS=-lasan -lubsan -llsan
endif endif
RM=rm -f RM=rm -f
FIND=find FIND=find
INCLUDES=-Ilibstrophe INCLUDES=-Ilibstrophe
CFLAGS+=$(DBGCFLAGS) -fno-omit-frame-pointer -fPIC -std=gnu99 -g -Wall -Wextra -Werror-implicit-function-declaration -Wno-missing-field-initializers $(INCLUDES) CFLAGS+=$(DBGCFLAGS) -fno-omit-frame-pointer -fPIC -std=gnu99 -g -Wall -Wextra -Werror-implicit-function-declaration -Wno-missing-field-initializers $(INCLUDES)
LDFLAGS+=-shared -g $(DBGCFLAGS) $(DBGLDFLAGS) LDFLAGS+=$(DBGLDFLAGS) -shared -g $(DBGCFLAGS)
LDLIBS=-lstrophe -lpthread LDLIBS=-lstrophe -lpthread
PREFIX ?= /usr/local PREFIX ?= /usr/local
@ -14,19 +14,35 @@ LIBDIR ?= $(PREFIX)/lib
INSTALL ?= /usr/bin/install INSTALL ?= /usr/bin/install
SRCS=plugin.c \ SRCS=plugin.c \
account.c \
buffer.c \
channel.c \
command.c \ command.c \
config.c \ config.c \
connection.c \ connection.c \
input.c \
message.c \
user.c \
DEPS= DEPS=
OBJS=$(subst .c,.o,$(SRCS)) OBJS=$(subst .c,.o,$(SRCS))
all: $(DEPS) weechat-xmpp all: weechat-xmpp
weechat-xmpp: $(DEPS) xmpp.so
weechat-xmpp: $(OBJS) xmpp.so: $(OBJS)
$(CC) $(LDFLAGS) -o xmpp.so $(OBJS) $(LDLIBS) $(CC) $(LDFLAGS) -o xmpp.so $(OBJS) $(LDLIBS)
which patchelf >/dev/null && \ which patchelf >/dev/null && \
patchelf --set-rpath $(LIBRARY_PATH):$(shell patchelf --print-rpath xmpp.so) xmpp.so || true patchelf --set-rpath $(LIBRARY_PATH):$(shell realpath $(shell dirname $(shell gcc --print-libgcc-file-name))/../../../) xmpp.so && \
patchelf --shrink-rpath xmpp.so || true
test: xmpp.so
env LD_PRELOAD=$(DEBUG) \
weechat -a -P buflist -r '/plugin load ./xmpp.so'
debug: xmpp.so
gdb -ex "handle SIGPIPE nostop noprint pass" --args \
weechat -a -r '/plugin load ./xmpp.so'
depend: .depend depend: .depend

@ -0,0 +1,495 @@
// 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 <strophe.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "config.h"
#include "input.h"
#include "account.h"
#include "connection.h"
//#include "xmpp-api.h"
//#include "xmpp-request.h"
#include "user.h"
#include "channel.h"
#include "buffer.h"
struct t_account *accounts = NULL;
struct t_account *last_account = NULL;
char *account_options[ACCOUNT_NUM_OPTIONS][2] =
{ { "jid", "" },
{ "password", "" },
{ "tls", "normal" },
{ "nickname", "" },
};
struct t_account *account__search(const char *name)
{
struct t_account *ptr_account;
if (!name)
return NULL;
for (ptr_account = accounts; ptr_account;
ptr_account = ptr_account->next_account)
{
if (strcmp(ptr_account->name, name) == 0)
return ptr_account;
}
/* account not found */
return NULL;
}
struct t_account *account__casesearch (const char *name)
{
struct t_account *ptr_account;
if (!name)
return NULL;
for (ptr_account = accounts; ptr_account;
ptr_account = ptr_account->next_account)
{
if (weechat_strcasecmp (ptr_account->name, name) == 0)
return ptr_account;
}
/* account not found */
return NULL;
}
int account__search_option(const char *option_name)
{
int i;
if (!option_name)
return -1;
for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
{
if (weechat_strcasecmp(account_options[i][0], option_name) == 0)
return i;
}
/* account option not found */
return -1;
}
void log_emit_weechat(void *const userdata, const xmpp_log_level_t level,
const char *const area, const char *const msg)
{
struct t_account *account = (struct t_account*)userdata;
static const char *log_level_name[4] = {"debug", "info", "warn", "error"};
time_t date = time(NULL);
const char *timestamp = weechat_util_get_time_string(&date);
weechat_printf(
account ? account->buffer : NULL,
_("%s%s (%s): %s"),
weechat_prefix("error"), area,
log_level_name[level], msg);
}
struct t_account *account__alloc(const char *name)
{
struct t_account *new_account;
int i, length;
char *option_name;
if (account__casesearch(name))
return NULL;
/* alloc memory for new account */
new_account = malloc(sizeof(*new_account));
if (!new_account)
{
weechat_printf(NULL,
_("%s%s: error when allocating new account"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
return NULL;
}
/* add new account to queue */
new_account->prev_account = last_account;
new_account->next_account = NULL;
if (last_account)
last_account->next_account = new_account;
else
accounts = new_account;
last_account = new_account;
/* set name */
new_account->name = strdup(name);
/* set properties */
new_account->jid = NULL;
new_account->password = NULL;
new_account->tls = 1;
/* internal vars */
new_account->reloading_from_config = 0;
new_account->is_connected = 0;
new_account->disconnected = 0;
new_account->logger.handler = &log_emit_weechat;
new_account->logger.userdata = new_account;
new_account->context = xmpp_ctx_new(NULL, &new_account->logger);
new_account->connection = NULL;
new_account->nickname = NULL;
new_account->buffer = NULL;
new_account->buffer_as_string = NULL;
new_account->users = NULL;
new_account->last_user = NULL;
new_account->channels = NULL;
new_account->last_channel = NULL;
/* create options with null value */
for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
{
new_account->options[i] = NULL;
length = strlen(new_account->name) + 1 +
strlen(account_options[i][0]) +
512 + /* inherited option name(xmpp.account_default.xxx) */
1;
option_name = malloc(length);
if (option_name)
{
snprintf(option_name, length, "%s.%s << xmpp.account_default.%s",
new_account->name,
account_options[i][0],
account_options[i][0]);
new_account->options[i] = config__account_new_option(
config_file,
config_section_account,
i,
option_name,
account_options[i][1],
account_options[i][1],
0,
&config__account_check_value_cb,
account_options[i][0],
NULL,
&config__account_change_cb,
account_options[i][0],
NULL);
config__account_change_cb(account_options[i][0], NULL,
new_account->options[i]);
free(option_name);
}
}
return new_account;
}
void account__free_data(struct t_account *account)
{
int i;
if (!account)
return;
/* free linked lists */
/*
for (i = 0; i < IRC_SERVER_NUM_OUTQUEUES_PRIO; i++)
{
account__outqueue_free_all(account, i);
}
xmpp_redirect_free_all(account);
xmpp_notify_free_all(account);
*/
channel__free_all(account);
user__free_all(account);
/* free hashtables */
/*
weechat_hashtable_free(account->join_manual);
weechat_hashtable_free(account->join_channel_key);
weechat_hashtable_free(account->join_noswitch);
*/
/* close xmpp context */
if (account->connection)
xmpp_conn_release(account->connection);
if (account->context)
xmpp_ctx_free(account->context);
/* free account data */
//for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
//{
// if (account->options[i])
// weechat_config_option_free(account->options[i]);
//}
if (account->name)
free(account->name);
if (account->jid)
free(account->jid);
if (account->password)
free(account->password);
if (account->nickname)
free(account->nickname);
if (account->buffer_as_string)
free(account->buffer_as_string);
channel__free_all(account);
user__free_all(account);
}
void account__free(struct t_account *account)
{
struct t_account *new_accounts;
if (!account)
return;
/*
* close account buffer (and all channels/privates)
* (only if we are not in a /upgrade, because during upgrade we want to
* keep connections and closing account buffer would disconnect from account)
*/
if (account->buffer)
weechat_buffer_close(account->buffer);
/* remove account from queue */
if (last_account == account)
last_account = account->prev_account;
if (account->prev_account)
{
(account->prev_account)->next_account = account->next_account;
new_accounts = accounts;
}
else
new_accounts = account->next_account;
if (account->next_account)
(account->next_account)->prev_account = account->prev_account;
account__free_data(account);
free(account);
accounts = new_accounts;
}
void account__free_all()
{
/* for each account in memory, remove it */
while (accounts)
{
account__free(accounts);
}
}
void account__disconnect(struct t_account *account, int reconnect)
{
(void) reconnect;
struct t_channel *ptr_channel;
(void) ptr_channel;
if (account->is_connected)
{
/*
* remove all nicks and write disconnection message on each
* channel/private buffer
*/
user__free_all(account);
weechat_nicklist_remove_all(account->buffer);
for (ptr_channel = account->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 account"),
weechat_prefix("network"), WEECHAT_XMPP_PLUGIN_NAME);
}
/* remove away status on account buffer */
//weechat_buffer_set(account->buffer, "localvar_del_away", "");
}
account__close_connection(account);
if (account->buffer)
{
weechat_printf(
account->buffer,
_("%s%s: disconnected from account"),
weechat_prefix ("network"), WEECHAT_XMPP_PLUGIN_NAME);
}
/*
account->current_retry = 0;
if (switch_address)
account__switch_address(account, 0);
else
account__set_index_current_address(account, 0);
if (account->nick_modes)
{
free (account->nick_modes);
account->nick_modes = NULL;
weechat_bar_item_update ("input_prompt");
weechat_bar_item_update ("xmpp_nick_modes");
}
account->cap_away_notify = 0;
account->cap_account_notify = 0;
account->cap_extended_join = 0;
account->is_away = 0;
account->away_time = 0;
account->lag = 0;
account->lag_displayed = -1;
account->lag_check_time.tv_sec = 0;
account->lag_check_time.tv_usec = 0;
account->lag_next_check = time (NULL) +
weechat_config_integer (xmpp_config_network_lag_check);
account->lag_last_refresh = 0;
account__set_lag (account);
account->monitor = 0;
account->monitor_time = 0;
if (reconnect
&& IRC_SERVER_OPTION_BOOLEAN(account, IRC_SERVER_OPTION_AUTORECONNECT))
account__reconnect_schedule(account);
else
{
account->reconnect_delay = 0;
account->reconnect_start = 0;
}
*/
/* discard current nick if no reconnection asked */
/*
if (!reconnect && account->nick)
account__set_nick(account, NULL);
account__set_buffer_title(account);
account->disconnected = 1;
*/
/* send signal "account_disconnected" with account name */
/*
(void) weechat_hook_signal_send("account_disconnected",
WEECHAT_HOOK_SIGNAL_STRING, account->name);
*/
}
void account__disconnect_all()
{
struct t_account *ptr_account;
for (ptr_account = accounts; ptr_account;
ptr_account = ptr_account->next_account)
{
account__disconnect(ptr_account, 0);
}
}
struct t_gui_buffer *account__create_buffer(struct t_account *account)
{
char buffer_name[256], charset_modifier[256];
snprintf(buffer_name, sizeof(buffer_name),
"account.%s", account->name);
account->buffer = weechat_buffer_new(buffer_name,
&input__data_cb, NULL, NULL,
&buffer__close_cb, NULL, NULL);
if (!account->buffer)
return NULL;
if (!weechat_buffer_get_integer(account->buffer, "short_name_is_set"))
weechat_buffer_set(account->buffer, "short_name", account->name);
weechat_buffer_set(account->buffer, "localvar_set_type", "server");
weechat_buffer_set(account->buffer, "localvar_set_server", account->name);
weechat_buffer_set(account->buffer, "localvar_set_channel", account->name);
snprintf(charset_modifier, sizeof (charset_modifier),
"account.%s", account->name);
weechat_buffer_set(account->buffer, "localvar_set_charset_modifier",
charset_modifier);
weechat_buffer_set(account->buffer, "title",
(account->name) ? account->name : "");
weechat_buffer_set(account->buffer, "nicklist", "1");
weechat_buffer_set(account->buffer, "nicklist_display_groups", "0");
weechat_buffer_set_pointer(account->buffer, "nicklist_callback",
&buffer__nickcmp_cb);
weechat_buffer_set_pointer(account->buffer, "nicklist_callback_pointer",
account);
return account->buffer;
}
void account__close_connection(struct t_account *account)
{
if (account->connection)
{
if (xmpp_conn_is_connected(account->connection))
xmpp_disconnect(account->connection);
}
account->is_connected = 0;
}
int account__connect(struct t_account *account)
{
account->disconnected = 0;
if (!account->buffer)
{
if (!account__create_buffer(account))
return 0;
weechat_buffer_set(account->buffer, "display", "auto");
}
account__close_connection(account);
account->jid = !account->options[ACCOUNT_OPTION_JID] ? NULL :
weechat_config_string(account->options[ACCOUNT_OPTION_JID]);
account->password = !account->options[ACCOUNT_OPTION_PASSWORD] ? NULL :
weechat_config_string(account->options[ACCOUNT_OPTION_PASSWORD]);
account->tls = !account->options[ACCOUNT_OPTION_TLS] ? NULL :
weechat_config_integer(account->options[ACCOUNT_OPTION_TLS]);
account->nickname = !account->options[ACCOUNT_OPTION_NICKNAME] ? NULL :
weechat_config_string(account->options[ACCOUNT_OPTION_NICKNAME]);
account->is_connected =
connection__connect(account->context, &account->connection,
&account->logger, account->jid,
account->password, account->tls);
return account->is_connected;
}
int account__timer_cb(const void *pointer, void *data, int remaining_calls)
{
(void) pointer;
(void) data;
(void) remaining_calls;
struct t_account *ptr_account;
for (ptr_account = accounts; ptr_account;
ptr_account = ptr_account->next_account)
{
if (ptr_account->is_connected
&& (xmpp_conn_is_connecting(ptr_account->connection)
|| xmpp_conn_is_connected(ptr_account->connection)))
connection__process(ptr_account->context, ptr_account->connection, 10);
}
}

@ -0,0 +1,64 @@
// 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 _ACCOUNT_H_
#define _ACCOUNT_H_
extern struct t_account *accounts;
extern struct t_account *last_account;
enum t_account_option
{
ACCOUNT_OPTION_JID,
ACCOUNT_OPTION_PASSWORD,
ACCOUNT_OPTION_TLS,
ACCOUNT_OPTION_NICKNAME,
ACCOUNT_NUM_OPTIONS,
};
struct t_account
{
const char *name;
const char *jid;
const char *password;
int tls;
struct t_config_option *options[ACCOUNT_NUM_OPTIONS];
int reloading_from_config;
int is_connected;
int disconnected;
xmpp_log_t logger;
struct xmpp_ctx_t *context;
struct xmpp_conn_t *connection;
char *nickname;
struct t_gui_buffer *buffer;
char *buffer_as_string;
struct t_user *users;
struct t_user *last_user;
struct t_channel *channels;
struct t_channel *last_channel;
struct t_account *prev_account;
struct t_account *next_account;
};
extern char *account_options[][2];
struct t_account *account__search(const char *account_name);
struct t_account *account__casesearch (const char *account_name);
int account__search_option(const char *option_name);
struct t_account *account__alloc(const char *name);
void account__free_data(struct t_account *account);
void account__free(struct t_account *account);
void account__free_all();
void account__disconnect(struct t_account *account, int reconnect);
void account__disconnect_all();
void account__close_connection(struct t_account *account);
int account__connect(struct t_account *account);
int account__timer_cb(const void *pointer, void *data, int remaining_calls);
#endif /*ACCOUNT_H*/

@ -0,0 +1,165 @@
// 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 <strophe.h>
#include <string.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "account.h"
#include "channel.h"
#include "buffer.h"
void buffer__get_account_and_channel(struct t_gui_buffer *buffer,
struct t_account **account,
struct t_channel **channel)
{
struct t_account *ptr_account;
struct t_channel *ptr_channel;
if (!buffer)
return;
/* look for a account or channel using this buffer */
for (ptr_account = accounts; ptr_account;
ptr_account = ptr_account->next_account)
{
if (ptr_account->buffer == buffer)
{
if (account)
*account = ptr_account;
return;
}
for (ptr_channel = ptr_account->channels; ptr_channel;
ptr_channel = ptr_channel->next_channel)
{
if (ptr_channel->buffer == buffer)
{
if (account)
*account = ptr_account;
if (channel)
*channel = ptr_channel;
return;
}
}
}
/* no account or channel found */
}
char *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_channel_typing *ptr_typing;
struct t_account *account;
struct t_channel *channel;
char notification[256];
unsigned typecount;
(void) pointer;
(void) data;
(void) item;
(void) window;
(void) extra_info;
account = NULL;
channel = NULL;
buffer__get_account_and_channel(buffer, &account, &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 buffer__nickcmp_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *nick1,
const char *nick2)
{
struct t_account *account;
(void) data;
if (pointer)
account = (struct t_account *)pointer;
else
buffer__get_account_and_channel(buffer, &account, NULL);
if (account)
{
return weechat_strcasecmp(nick1, nick2);
}
else
{
return weechat_strcasecmp(nick1, nick2);
}
}
int buffer__close_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer)
{
struct t_weechat_plugin *buffer_plugin = NULL;
struct t_account *ptr_account = NULL;
struct t_channel *ptr_channel = NULL;
buffer_plugin = weechat_buffer_get_pointer(buffer, "plugin");
if (buffer_plugin == weechat_plugin)
buffer__get_account_and_channel(buffer,
&ptr_account, &ptr_channel);
(void) pointer;
(void) data;
(void) buffer;
if (ptr_account)
{
if (!ptr_account->disconnected)
{
//command_quit_account(ptr_account, NULL);
account__disconnect(ptr_account, 0);
}
ptr_account->buffer = NULL;
}
return WEECHAT_RC_OK;
}

@ -0,0 +1,27 @@
// 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 _WEECHAT_XMPP_BUFFER_H_
#define _WEECHAT_XMPP_BUFFER_H_
void buffer__get_account_and_channel(struct t_gui_buffer *buffer,
struct t_account **account,
struct t_channel **channel);
char *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 buffer__nickcmp_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *nick1,
const char *nick2);
int buffer__close_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer);
#endif /*WEECHAT_XMPP_BUFFER_H*/

@ -0,0 +1,643 @@
// 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 <strophe.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "account.h"
#include "user.h"
#include "channel.h"
#include "input.h"
#include "buffer.h"
struct t_channel *channel__search(struct t_account *account,
const char *id)
{
struct t_channel *ptr_channel;
if (!account || !id)
return NULL;
for (ptr_channel = account->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 *channel__search_buffer(struct t_account *account,
enum t_channel_type type,
const char *name)
{
struct t_hdata *hdata_buffer;
struct t_gui_buffer *ptr_buffer;
const char *ptr_type, *ptr_account_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_plugin)
{
ptr_type = weechat_buffer_get_string(ptr_buffer, "localvar_type");
ptr_account_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_account_name && ptr_account_name[0]
&& ptr_channel_name && ptr_channel_name[0]
&& ( (( (type == CHANNEL_TYPE_CHANNEL)
|| (type == CHANNEL_TYPE_GROUP))
&& (strcmp(ptr_type, "channel") == 0))
|| (( (type == CHANNEL_TYPE_MPIM)
|| (type == CHANNEL_TYPE_IM))
&& (strcmp(ptr_type, "private") == 0)))
&& (strcmp(ptr_account_name, account->name) == 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 *channel__create_buffer(struct t_account *account,
enum t_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", account->name, name);
ptr_buffer = channel__search_buffer(account, type, name);
if (ptr_buffer)
{
weechat_nicklist_remove_all(ptr_buffer);
}
else
{
ptr_buffer = weechat_buffer_new(buffer_name,
&input__data_cb, NULL, NULL,
&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 == CHANNEL_TYPE_IM ||
type == CHANNEL_TYPE_MPIM) ? "private" : "channel");
weechat_buffer_set(ptr_buffer, "localvar_set_nick", account->nickname);
weechat_buffer_set(ptr_buffer, "localvar_set_server", account->name);
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 != 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",
&buffer__nickcmp_cb);
weechat_buffer_set_pointer(ptr_buffer, "nicklist_callback_pointer",
account);
}
weechat_buffer_set(ptr_buffer, "highlight_words_add",
account->nickname);
weechat_buffer_set(ptr_buffer, "highlight_tags_restrict",
"message");
}
return ptr_buffer;
}
void channel__add_nicklist_groups(struct t_account *account,
struct t_channel *channel)
{
struct t_gui_buffer *ptr_buffer;
char str_group[32];
if (channel && channel->type == CHANNEL_TYPE_MPIM)
return;
if (channel && channel->type == CHANNEL_TYPE_IM)
return;
ptr_buffer = channel ? channel->buffer : account->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_channel *channel__new(struct t_account *account,
enum t_channel_type type,
const char *id, const char *name)
{
struct t_channel *new_channel, *ptr_channel;
struct t_gui_buffer *ptr_buffer;
struct t_hook *typing_timer;
char buffer_name[CHANNEL_NAME_MAX_LEN + 2];
if (!account || !id || !name || !name[0])
return NULL;
ptr_channel = channel__search(account, id);
if (ptr_channel)
{
return ptr_channel;
}
buffer_name[0] = '#';
strncpy(&buffer_name[1], name, CHANNEL_NAME_MAX_LEN + 1);
ptr_buffer = channel__create_buffer(account, 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,
&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 = account->last_channel;
new_channel->next_channel = NULL;
if (account->last_channel)
(account->last_channel)->next_channel = new_channel;
else
account->channels = new_channel;
account->last_channel = new_channel;
return new_channel;
}
void channel__member_speaking_add_to_list(struct t_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 > CHANNEL_MEMBERS_SPEAKING_LIMIT)
{
to_remove = size - 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 channel__member_speaking_add(struct t_channel *channel,
const char *nick, int highlight)
{
if (highlight < 0)
highlight = 0;
if (highlight > 1)
highlight = 1;
if (highlight)
channel__member_speaking_add_to_list(channel, nick, 1);
channel__member_speaking_add_to_list(channel, nick, 0);
}
void channel__member_speaking_rename(struct t_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 channel__member_speaking_rename_if_present(struct t_account *account,
struct t_channel *channel,
const char *nick)
{
struct t_weelist_item *ptr_item;
int i, j, list_size;
(void) account;
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 channel__typing_free(struct t_channel *channel,
struct t_channel_typing *typing)
{
struct t_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 channel__typing_free_all(struct t_channel *channel)
{
while (channel->typings)
channel__typing_free(channel, channel->typings);
}
int channel__typing_cb(const void *pointer,
void *data,
int remaining_calls)
{
struct t_channel_typing *ptr_typing, *next_typing;
struct t_channel *channel;
const char *localvar;
unsigned typecount;
time_t now;
(void) data;
(void) remaining_calls;
if (!pointer)
return WEECHAT_RC_ERROR;
channel = (struct t_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)
{
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("typing");
return WEECHAT_RC_OK;
}
struct t_channel_typing *channel__typing_search(
struct t_channel *channel,
const char *id)
{
struct t_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 channel__add_typing(struct t_channel *channel,
struct t_user *user)
{
struct t_channel_typing *new_typing;
new_typing = 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);
channel__typing_cb(channel, NULL, 0);
}
void channel__member_free(struct t_channel *channel,
struct t_channel_member *member)
{
struct t_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 channel__member_free_all(struct t_channel *channel)
{
while (channel->members)
channel__member_free(channel, channel->members);
}
void channel__free(struct t_account *account,
struct t_channel *channel)
{
struct t_channel *new_channels;
if (!account || !channel)
return;
/* remove channel from channels list */
if (account->last_channel == channel)
account->last_channel = channel->prev_channel;
if (channel->prev_channel)
{
(channel->prev_channel)->next_channel = channel->next_channel;
new_channels = account->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 */
channel__typing_free_all(channel);
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);
account->channels = new_channels;
}
void channel__free_all(struct t_account *account)
{
while (account->channels)
channel__free(account, account->channels);
}
void channel__update_topic(struct t_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 channel__update_purpose(struct t_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_channel_member *channel__add_member(
struct t_account *account,
struct t_channel *channel,
const char *id)
{
struct t_channel_member *member;
struct t_user *user;
member = malloc(sizeof(struct t_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 = user__search(account, id);
if (user)
user__nicklist_add(account, channel, user);
return member;
}

@ -0,0 +1,147 @@
// 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 _WEECHAT_XMPP_CHANNEL_H_
#define _WEECHAT_XMPP_CHANNEL_H_
#define CHANNEL_MEMBERS_SPEAKING_LIMIT 128
#define CHANNEL_NAME_MAX_LEN 22
enum t_channel_type
{
CHANNEL_TYPE_CHANNEL,
CHANNEL_TYPE_GROUP,
CHANNEL_TYPE_MPIM,
CHANNEL_TYPE_IM,
};
struct t_channel_typing
{
char *id;
char *name;
time_t ts;
struct t_channel_typing *prev_typing;
struct t_channel_typing *next_typing;
};
struct t_channel_member
{
char *id;
struct t_channel_member *prev_member;
struct t_channel_member *next_member;
};
struct t_channel_topic
{
char *value;
char *creator;
time_t last_set;
};
struct t_channel_purpose
{
char *value;
char *creator;
time_t last_set;
};
struct t_channel
{
enum t_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_channel_topic topic;
struct t_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_channel_typing *typings;
struct t_channel_typing *last_typing;
struct t_channel_member *members;
struct t_channel_member *last_member;
struct t_gui_buffer *buffer;
char *buffer_as_string;
struct t_channel *prev_channel;
struct t_channel *next_channel;
};
struct t_channel *channel__search(struct t_account *account,
const char *id);
void channel__add_nicklist_groups(struct t_account *account,
struct t_channel *channel);
struct t_channel *channel__new(struct t_account *account,
enum t_channel_type type,
const char *id, const char *name);
void channel__member_speaking_add(struct t_channel *channel,
const char *nick, int highlight);
void channel__member_speaking_rename(struct t_channel *channel,
const char *old_nick,
const char *new_nick);
void channel__member_speaking_rename_if_present(struct t_account *account,
struct t_channel *channel,
const char *nick);
void channel__typing_free(struct t_channel *channel,
struct t_channel_typing *typing);
void channel__typing_free_all(struct t_channel *channel);
int channel__typing_cb(const void *pointer,
void *data,
int remaining_calls);
struct t_channel_typing *channel__typing_search(
struct t_channel *channel,
const char *id);
void channel__add_typing(struct t_channel *channel,
struct t_user *user);
void channel__free_all(struct t_account *account);
void channel__update_topic(struct t_channel *channel,
const char* title,
const char* creator,
int last_set);
void channel__update_purpose(struct t_channel *channel,
const char* purpose,
const char* creator,
int last_set);
struct t_channel_member *channel__add_member(
struct t_account *account,
struct t_channel *channel,
const char *id);
#endif /*WEECHAT_XMPP_CHANNEL_H*/

@ -8,39 +8,35 @@
#include <weechat/weechat-plugin.h> #include <weechat/weechat-plugin.h>
#include "plugin.h" #include "plugin.h"
//#include "xmpp-oauth.h" //#include "oauth.h"
//#include "xmpp-teaminfo.h" //#include "teaminfo.h"
//#include "xmpp-workspace.h" #include "account.h"
//#include "xmpp-channel.h" #include "channel.h"
//#include "xmpp-buffer.h" #include "buffer.h"
//#include "xmpp-message.h" #include "message.h"
#include "command.h" #include "command.h"
//#include "request/xmpp-request-chat-memessage.h"
/* void command__display_account(struct t_account *account)
void xmpp_command_display_workspace(xmpp_conn_t *workspace)
{ {
int num_channels, num_pv; int num_channels, num_pv;
if (workspace->is_connected) if (account->is_connected)
{ {
num_channels = 0;//xmpp_workspace_get_channel_count(workspace); num_channels = 0;//xmpp_account_get_channel_count(account);
num_pv = 0;//xmpp_workspace_get_pv_count(workspace); num_pv = 0;//xmpp_account_get_pv_count(account);
weechat_printf( weechat_printf(
NULL, NULL,
" %s %s%s%s.xmpp.com %s(%s%s%s) [%s%s%s]%s, %d %s, %d pv", " %s %s%s%s %s(%s%s%s) [%s%s%s]%s, %d %s, %d pv",
(workspace->is_connected) ? "*" : " ", (account->is_connected) ? "*" : " ",
weechat_color("chat_server"), weechat_color("chat_server"),
workspace->domain, account->name,
weechat_color("reset"), weechat_color("reset"),
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("chat_server"), weechat_color("chat_server"),
(workspace->name) ? (account->jid) ? account->jid : "???",
workspace->name : "???",
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("reset"), weechat_color("reset"),
(workspace->is_connected) ? (account->is_connected) ? _("connected") : _("not connected"),
_("connected") : _("not connected"),
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("reset"), weechat_color("reset"),
num_channels, num_channels,
@ -51,177 +47,166 @@ void xmpp_command_display_workspace(xmpp_conn_t *workspace)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
" %s%s%s.xmpp.com %s(%s%s%s)%s", " %s%s%s %s(%s%s%s)%s",
weechat_color("chat_server"), weechat_color("chat_server"),
workspace->domain, account->name,
weechat_color("reset"), weechat_color("reset"),
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("chat_server"), weechat_color("chat_server"),
(workspace->name) ? (account->jid) ? account->jid : "???",
workspace->name : "???",
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("reset")); weechat_color("reset"));
} }
} }
void xmpp_command_workspace_list(int argc, char **argv) void command__account_list(int argc, char **argv)
{ {
int i, one_workspace_found; int i, one_account_found;
xmpp_conn_t *ptr_workspace2; struct t_account *ptr_account2;
char *workspace_name = NULL; char *account_name = NULL;
for (i = 2; i < argc; i++) for (i = 2; i < argc; i++)
{ {
if (!workspace_name) if (!account_name)
workspace_name = argv[i]; account_name = argv[i];
} }
if (!workspace_name) if (!account_name)
{ {
if (xmpp_workspaces) if (accounts)
{ {
weechat_printf(NULL, ""); weechat_printf(NULL, "");
weechat_printf(NULL, _("All workspaces:")); weechat_printf(NULL, _("All accounts:"));
for (ptr_workspace2 = xmpp_workspaces; ptr_workspace2; for (ptr_account2 = accounts; ptr_account2;
ptr_workspace2 = ptr_workspace2->next_workspace) ptr_account2 = ptr_account2->next_account)
{ {
xmpp_command_display_workspace(ptr_workspace2); command__display_account(ptr_account2);
} }
} }
else else
weechat_printf(NULL, _("No workspace")); weechat_printf(NULL, _("No account"));
} }
else else
{ {
one_workspace_found = 0; one_account_found = 0;
for (ptr_workspace2 = xmpp_workspaces; ptr_workspace2; for (ptr_account2 = accounts; ptr_account2;
ptr_workspace2 = ptr_workspace2->next_workspace) ptr_account2 = ptr_account2->next_account)
{ {
if (weechat_strcasestr(ptr_workspace2->name, workspace_name)) if (weechat_strcasestr(ptr_account2->name, account_name))
{ {
if (!one_workspace_found) if (!one_account_found)
{ {
weechat_printf(NULL, ""); weechat_printf(NULL, "");
weechat_printf(NULL, weechat_printf(NULL,
_("Servers with \"%s\":"), _("Servers with \"%s\":"),
workspace_name); account_name);
} }
one_workspace_found = 1; one_account_found = 1;
xmpp_command_display_workspace(ptr_workspace2); command__display_account(ptr_account2);
} }
} }
if (!one_workspace_found) if (!one_account_found)
weechat_printf(NULL, weechat_printf(NULL,
_("No workspace found with \"%s\""), _("No account found with \"%s\""),
workspace_name); account_name);
} }
} }
void xmpp_command_add_workspace(struct t_xmpp_teaminfo *xmpp_teaminfo) void command__add_account(const char *name, const char *jid, const char *password)
{ {
xmpp_conn_t *workspace; struct t_account *account;
workspace = xmpp_workspace_casesearch(xmpp_teaminfo->domain); account = account__casesearch(name);
if (workspace) if (account)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: workspace \"%s\" already exists, can't add it!"), _("%s%s: account \"%s\" already exists, can't add it!"),
weechat_prefix("error"), XMPP_PLUGIN_NAME, weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
xmpp_teaminfo->domain); name);
return; return;
} }
workspace = xmpp_workspace_alloc(xmpp_teaminfo->domain); account = account__alloc(name);
if (!workspace) if (!account)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: unable to add workspace"), _("%s%s: unable to add account"),
weechat_prefix("error"), XMPP_PLUGIN_NAME); weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
return; return;
} }
workspace->id = strdup(xmpp_teaminfo->id); account->name = strdup(name);
workspace->name = strdup(xmpp_teaminfo->name); if (jid)
weechat_config_option_set(workspace->options[XMPP_WORKSPACE_OPTION_TOKEN], account->jid = strdup(jid);
xmpp_teaminfo->token, 1); if (password)
account->password = strdup(password);
weechat_config_option_set(account->options[ACCOUNT_OPTION_JID],
account->jid, 1);
weechat_config_option_set(account->options[ACCOUNT_OPTION_PASSWORD],
account->password, 1);
weechat_config_option_set(account->options[ACCOUNT_OPTION_NICKNAME],
account->jid ? xmpp_jid_node(account->context,
account->jid)
: NULL, 1);
weechat_printf ( weechat_printf (
NULL, NULL,
_("%s: workspace %s%s%s.xmpp.com %s(%s%s%s)%s added"), _("%s: account %s%s%s %s(%s%s%s)%s added"),
XMPP_PLUGIN_NAME, WEECHAT_XMPP_PLUGIN_NAME,
weechat_color("chat_server"), weechat_color("chat_server"),
workspace->domain, account->name,
weechat_color("reset"), weechat_color("reset"),
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("chat_server"), weechat_color("chat_server"),
workspace->name, account->jid ? account->jid : "???",
weechat_color("chat_delimiters"), weechat_color("chat_delimiters"),
weechat_color("reset")); weechat_color("reset"));
free_teaminfo(xmpp_teaminfo);
} }
void xmpp_command_fetch_workspace(char *token) void command__account_add(int argc, char **argv)
{ {
xmpp_teaminfo_fetch(token, &xmpp_command_add_workspace); char *name, *jid = NULL, *password = NULL;
free(token);
}
void xmpp_command_workspace_register(int argc, char **argv)
{
char *code;
if (argc > 2)
{
code = argv[2];
if (strncmp("xoxp", code, 4) == 0) switch (argc)
{ {
xmpp_command_fetch_workspace(strdup(code)); case 5:
} password = argv[4];
else case 4:
{ jid = argv[3];
xmpp_oauth_request_token(code, &xmpp_command_fetch_workspace); case 3:
} name = argv[2];
} command__add_account(name, jid, password);
else break;
{ default:
weechat_printf(NULL, weechat_printf(NULL, _("account add: wrong number of arguments"));
_("\n#### Retrieving a Xmpp token via OAUTH ####\n" break;
"1) Paste this into a browser: https://xmpp.com/oauth/authorize?client_id=%s&scope=client\n"
"2) Select the team you wish to access from weechat in your browser.\n"
"3) Click \"Authorize\" in the browser **IMPORTANT: the redirect will fail, this is expected**\n"
"4) Copy the \"code\" portion of the URL to your clipboard\n"
"5) Return to weechat and run `/xmpp register [code]`\n"),
XMPP_CLIENT_ID);
} }
} }
int xmpp_command_connect_workspace(xmpp_conn_t *workspace) int command__connect_account(struct t_account *account)
{ {
if (!workspace) if (!account)
return 0; return 0;
if (workspace->is_connected) if (account->is_connected)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: already connected to workspace \"%s\"!"), _("%s%s: already connected to account \"%s\"!"),
weechat_prefix("error"), XMPP_PLUGIN_NAME, weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
workspace->domain); account->name);
} }
xmpp_workspace_connect(workspace); account__connect(account);
return 1; return 1;
} }
int xmpp_command_workspace_connect(int argc, char **argv) int command__account_connect(int argc, char **argv)
{ {
int i, nb_connect, connect_ok; int i, nb_connect, connect_ok;
xmpp_conn_t *ptr_workspace; struct t_account *ptr_account;
(void) argc; (void) argc;
(void) argv; (void) argv;
@ -232,10 +217,10 @@ int xmpp_command_workspace_connect(int argc, char **argv)
for (i = 2; i < argc; i++) for (i = 2; i < argc; i++)
{ {
nb_connect++; nb_connect++;
ptr_workspace = xmpp_workspace_search(argv[i]); ptr_account = account__search(argv[i]);
if (ptr_workspace) if (ptr_account)
{ {
if (!xmpp_command_connect_workspace(ptr_workspace)) if (!command__connect_account(ptr_account))
{ {
connect_ok = 0; connect_ok = 0;
} }
@ -244,9 +229,9 @@ int xmpp_command_workspace_connect(int argc, char **argv)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: workspace not found \"%s\" " _("%s%s: account not found \"%s\" "
"(register first with: /xmpp register)"), "(add one first with: /account add)"),
weechat_prefix("error"), XMPP_PLUGIN_NAME, weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
argv[i]); argv[i]);
} }
} }
@ -254,10 +239,10 @@ int xmpp_command_workspace_connect(int argc, char **argv)
return (connect_ok) ? WEECHAT_RC_OK : WEECHAT_RC_ERROR; return (connect_ok) ? WEECHAT_RC_OK : WEECHAT_RC_ERROR;
} }
void xmpp_command_workspace_delete(int argc, char **argv) void command__account_delete(int argc, char **argv)
{ {
xmpp_conn_t *workspace; struct t_account *account;
char *workspace_domain; char *account_name;
if (argc < 3) if (argc < 3)
{ {
@ -270,42 +255,41 @@ void xmpp_command_workspace_delete(int argc, char **argv)
return; return;
} }
workspace = xmpp_workspace_search(argv[2]); account = account__search(argv[2]);
if (!workspace) if (!account)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: workspace \"%s\" not found for \"%s\" command"), _("%s%s: account \"%s\" not found for \"%s\" command"),
weechat_prefix("error"), XMPP_PLUGIN_NAME, weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
argv[2], "xmpp delete"); argv[2], "xmpp delete");
return; return;
} }
if (workspace->is_connected) if (account->is_connected)
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: you cannot delete workspace \"%s\" because you" _("%s%s: you cannot delete account \"%s\" because you"
"are connected. Try \"/xmpp disconnect %s\" first."), "are connected. Try \"/xmpp disconnect %s\" first."),
weechat_prefix("error"), XMPP_PLUGIN_NAME, weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
argv[2], argv[2]); argv[2], argv[2]);
return; return;
} }
workspace_domain = strdup(workspace->domain); account_name = strdup(account->name);
xmpp_workspace_free(workspace); account__free(account);
weechat_printf ( weechat_printf (
NULL, NULL,
_("%s: workspace %s%s%s has been deleted"), _("%s: account %s%s%s has been deleted"),
XMPP_PLUGIN_NAME, WEECHAT_XMPP_PLUGIN_NAME,
weechat_color("chat_server"), weechat_color("chat_server"),
(workspace_domain) ? workspace_domain : "???", (account_name) ? account_name : "???",
weechat_color("reset")); weechat_color("reset"));
if (workspace_domain) if (account_name)
free(workspace_domain); free(account_name);
} }
*/
int xmpp_command_xmpp(const void *pointer, void *data, int command__account(const void *pointer, void *data,
struct t_gui_buffer *buffer, int argc, struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol) char **argv, char **argv_eol)
{ {
@ -314,44 +298,44 @@ int xmpp_command_xmpp(const void *pointer, void *data,
(void) data; (void) data;
(void) buffer; (void) buffer;
//if (argc <= 1 || weechat_strcasecmp(argv[1], "list") == 0) if (argc <= 1 || weechat_strcasecmp(argv[1], "list") == 0)
//{ {
// xmpp_command_workspace_list(argc, argv); command__account_list(argc, argv);
// return WEECHAT_RC_OK; return WEECHAT_RC_OK;
//} }
//if (argc > 1) if (argc > 1)
//{ {
// if (weechat_strcasecmp(argv[1], "register") == 0) if (weechat_strcasecmp(argv[1], "add") == 0)
// { {
// xmpp_command_workspace_register(argc, argv); command__account_add(argc, argv);
// return WEECHAT_RC_OK; return WEECHAT_RC_OK;
// } }
// if (weechat_strcasecmp(argv[1], "connect") == 0) if (weechat_strcasecmp(argv[1], "connect") == 0)
// { {
// xmpp_command_workspace_connect(argc, argv); command__account_connect(argc, argv);
// return WEECHAT_RC_OK; return WEECHAT_RC_OK;
// } }
// if (weechat_strcasecmp(argv[1], "delete") == 0) if (weechat_strcasecmp(argv[1], "delete") == 0)
// { {
// xmpp_command_workspace_delete(argc, argv); command__account_delete(argc, argv);
// return WEECHAT_RC_OK; return WEECHAT_RC_OK;
// } }
// WEECHAT_COMMAND_ERROR; WEECHAT_COMMAND_ERROR;
//} }
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
int xmpp_command_me(const void *pointer, void *data, int command__me(const void *pointer, void *data,
struct t_gui_buffer *buffer, int argc, struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol) char **argv, char **argv_eol)
{ {
xmpp_conn_t *ptr_workspace = NULL; struct t_account *ptr_account = NULL;
//struct t_xmpp_channel *ptr_channel = NULL; struct t_xmpp_channel *ptr_channel = NULL;
//struct t_xmpp_request *request; //struct t_xmpp_request *request;
char *text; char *text;
@ -360,76 +344,72 @@ int xmpp_command_me(const void *pointer, void *data,
(void) buffer; (void) buffer;
(void) argv; (void) argv;
//xmpp_buffer_get_workspace_and_channel(buffer, &ptr_workspace, &ptr_channel); buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel);
//if (!ptr_workspace) if (!ptr_account)
// return WEECHAT_RC_ERROR; return WEECHAT_RC_ERROR;
//if (!ptr_channel) if (!ptr_channel)
//{ {
// weechat_printf ( weechat_printf (
// ptr_workspace->buffer, ptr_account->buffer,
// _("%s%s: \"%s\" command can not be executed on a workspace buffer"), _("%s%s: \"%s\" command can not be executed on a account buffer"),
// weechat_prefix("error"), XMPP_PLUGIN_NAME, "me"); weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "me");
// return WEECHAT_RC_OK; return WEECHAT_RC_OK;
//} }
//if (!ptr_workspace->is_connected) if (!ptr_account->is_connected)
//{ {
// weechat_printf(buffer, weechat_printf(buffer,
// _("%s%s: you are not connected to server"), _("%s%s: you are not connected to server"),
// weechat_prefix("error"), XMPP_PLUGIN_NAME); weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
// return WEECHAT_RC_OK; return WEECHAT_RC_OK;
//} }
//if (argc > 1) if (argc > 1)
//{ {
// text = malloc(XMPP_MESSAGE_MAX_LENGTH); text = argv_eol[1];
// if (!text)
// { //request = xmpp_request_chat_memessage(ptr_account,
// weechat_printf(buffer,
// _("%s%s: error allocating string"),
// weechat_prefix("error"), XMPP_PLUGIN_NAME);
// return WEECHAT_RC_ERROR;
// }
// lws_urlencode(text, argv_eol[1], XMPP_MESSAGE_MAX_LENGTH);
// request = xmpp_request_chat_memessage(ptr_workspace,
// weechat_config_string( // weechat_config_string(
// ptr_workspace->options[XMPP_WORKSPACE_OPTION_TOKEN]), // ptr_account->options[XMPP_ACCOUNT_OPTION_TOKEN]),
// ptr_channel->id, text); // ptr_channel->id, text);
// if (request) //if (request)
// xmpp_workspace_register_request(ptr_workspace, request); // xmpp_account_register_request(ptr_account, request);
}
// free(text);
//}
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
void xmpp_command_init() void command__init()
{ {
weechat_hook_command( struct t_hook *hook;
"xmpp",
N_("xmpp control"), hook = weechat_hook_command(
"account",
N_("handle xmpp accounts"),
N_("list" N_("list"
" || register [token]" " || add <account>"
" || connect <workspace>" " || connect <account>"
" || delete <workspace>"), " || delete <account>"),
N_(" list: list workspaces\n" N_(" list: list accounts\n"
"register: add a xmpp workspace\n" " add: add a xmpp account\n"
" connect: connect to a xmpp workspace\n" "connect: connect to a xmpp account\n"
" delete: delete a xmpp workspace\n"), " delete: delete a xmpp account\n"),
"list" "list"
" || register %(xmpp_token)" " || add %(xmpp_account)"
" || connect %(xmpp_workspace)" " || connect %(xmpp_account)"
" || delete %(xmpp_workspace)", " || delete %(xmpp_account)",
&xmpp_command_xmpp, NULL, NULL); &command__account, NULL, NULL);
if (!hook)
weechat_hook_command( weechat_printf(NULL, "Failed to setup command /account");
hook = weechat_hook_command(
"me", "me",
N_("send a xmpp action to the current channel"), N_("send a xmpp action to the current channel"),
N_("<message>"), N_("<message>"),
N_("message: message to send"), N_("message: message to send"),
NULL, &xmpp_command_me, NULL, NULL); NULL, &command__me, NULL, NULL);
if (!hook)
weechat_printf(NULL, "Failed to setup command /me");
} }

@ -5,6 +5,6 @@
#ifndef _WEECHAT_XMPP_COMMAND_H_ #ifndef _WEECHAT_XMPP_COMMAND_H_
#define _WEECHAT_XMPP_COMMAND_H_ #define _WEECHAT_XMPP_COMMAND_H_
extern void xmpp_command_init(); void command__init();
#endif /*WEECHAT_XMPP_COMMAND_H*/ #endif /*WEECHAT_XMPP_COMMAND_H*/

@ -8,21 +8,19 @@
#include <weechat/weechat-plugin.h> #include <weechat/weechat-plugin.h>
#include "plugin.h" #include "plugin.h"
#include "account.h"
#include "config.h" #include "config.h"
struct t_config_file *xmpp_config_file; struct t_config_file *config_file;
//struct t_config_section *xmpp_config_section_workspace_default; struct t_config_section *config_section_account_default;
//struct t_config_section *xmpp_config_section_workspace; struct t_config_section *config_section_account;
struct t_config_option *xmpp_config_server_jid; struct t_config_option *config_look_nick_completion_smart;
struct t_config_option *xmpp_config_server_password;
struct t_config_option *xmpp_config_look_nick_completion_smart;
/* struct t_config_option *config_account_default[ACCOUNT_NUM_OPTIONS];
struct t_config_option *xmpp_config_workspace_default[XMPP_WORKSPACE_NUM_OPTIONS];
int xmpp_config_workspace_check_value_cb(const void *pointer, void *data, int config__account_check_value_cb(const void *pointer, void *data,
struct t_config_option *option, struct t_config_option *option,
const char *value) const char *value)
{ {
@ -30,10 +28,11 @@ int xmpp_config_workspace_check_value_cb(const void *pointer, void *data,
(void) data; (void) data;
(void) option; (void) option;
(void) value; (void) value;
return 1; return 1;
} }
void xmpp_config_workspace_change_cb(const void *pointer, void *data, void config__account_change_cb(const void *pointer, void *data,
struct t_config_option *option) struct t_config_option *option)
{ {
(void) pointer; (void) pointer;
@ -41,7 +40,7 @@ void xmpp_config_workspace_change_cb(const void *pointer, void *data,
(void) option; (void) option;
} }
void xmpp_config_workspace_default_change_cb(const void *pointer, void *data, void config__account_default_change_cb(const void *pointer, void *data,
struct t_config_option *option) struct t_config_option *option)
{ {
(void) pointer; (void) pointer;
@ -50,7 +49,7 @@ void xmpp_config_workspace_default_change_cb(const void *pointer, void *data,
} }
struct t_config_option * struct t_config_option *
xmpp_config_workspace_new_option (struct t_config_file *config_file, config__account_new_option (struct t_config_file *config_file,
struct t_config_section *section, struct t_config_section *section,
int index_option, int index_option,
const char *option_name, const char *option_name,
@ -75,11 +74,59 @@ xmpp_config_workspace_new_option (struct t_config_file *config_file,
switch (index_option) switch (index_option)
{ {
case XMPP_WORKSPACE_OPTION_TOKEN: case ACCOUNT_OPTION_JID:
new_option = weechat_config_new_option (
config_file, section,
option_name, "string",
N_("XMPP Account JID"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
callback_check_value,
callback_check_value_pointer,
callback_check_value_data,
callback_change,
callback_change_pointer,
callback_change_data,
NULL, NULL, NULL);
break;
case ACCOUNT_OPTION_PASSWORD:
new_option = weechat_config_new_option (
config_file, section,
option_name, "string",
N_("XMPP Account Password"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
callback_check_value,
callback_check_value_pointer,
callback_check_value_data,
callback_change,
callback_change_pointer,
callback_change_data,
NULL, NULL, NULL);
break;
case ACCOUNT_OPTION_TLS:
new_option = weechat_config_new_option (
config_file, section,
option_name, "integer",
N_("XMPP Server TLS Policy"),
"disable|normal|trust", 0, 0,
default_value, value,
null_value_allowed,
callback_check_value,
callback_check_value_pointer,
callback_check_value_data,
callback_change,
callback_change_pointer,
callback_change_data,
NULL, NULL, NULL);
break;
case ACCOUNT_OPTION_NICKNAME:
new_option = weechat_config_new_option ( new_option = weechat_config_new_option (
config_file, section, config_file, section,
option_name, "string", option_name, "string",
N_("xmpp api token"), N_("XMPP Server JID"),
NULL, 0, 0, NULL, 0, 0,
default_value, value, default_value, value,
null_value_allowed, null_value_allowed,
@ -91,46 +138,46 @@ xmpp_config_workspace_new_option (struct t_config_file *config_file,
callback_change_data, callback_change_data,
NULL, NULL, NULL); NULL, NULL, NULL);
break; break;
case XMPP_WORKSPACE_NUM_OPTIONS: case ACCOUNT_NUM_OPTIONS:
break; break;
} }
return new_option; return new_option;
} }
void xmpp_config_workspace_create_default_options(struct t_config_section *section) void config__account_create_default_options(struct t_config_section *section)
{ {
int i; int i;
for (i = 0; i < XMPP_WORKSPACE_NUM_OPTIONS; i++) for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
{ {
xmpp_config_workspace_default[i] = xmpp_config_workspace_new_option( config_account_default[i] = config__account_new_option(
xmpp_config_file, config_file,
section, section,
i, i,
xmpp_workspace_options[i][0], account_options[i][0],
xmpp_workspace_options[i][1], account_options[i][1],
xmpp_workspace_options[i][1], account_options[i][1],
0, 0,
&xmpp_config_workspace_check_value_cb, &config__account_check_value_cb,
xmpp_workspace_options[i][0], account_options[i][0],
NULL, NULL,
&xmpp_config_workspace_default_change_cb, &config__account_default_change_cb,
xmpp_workspace_options[i][0], account_options[i][0],
NULL); NULL);
} }
} }
int xmpp_config_workspace_read_cb (const void *pointer, void *data, int config__account_read_cb (const void *pointer, void *data,
struct t_config_file *config_file, struct t_config_file *config_file,
struct t_config_section *section, struct t_config_section *section,
const char *option_name, const char *value) const char *option_name, const char *value)
{ {
struct t_xmpp_workspace *ptr_workspace; struct t_account *ptr_account;
int index_option, rc, i; int index_option, rc, i;
char *pos_option, *workspace_domain; char *pos_option, *account_name;
(void) pointer; (void) pointer;
(void) data; (void) data;
@ -144,42 +191,42 @@ int xmpp_config_workspace_read_cb (const void *pointer, void *data,
pos_option = strrchr(option_name, '.'); pos_option = strrchr(option_name, '.');
if (pos_option) if (pos_option)
{ {
workspace_domain = weechat_strndup(option_name, account_name = weechat_strndup(option_name,
pos_option - option_name); pos_option - option_name);
pos_option++; pos_option++;
if (workspace_domain) if (account_name)
{ {
index_option = xmpp_workspace_search_option(pos_option); index_option = account__search_option(pos_option);
if (index_option >= 0) if (index_option >= 0)
{ {
ptr_workspace = xmpp_workspace_search(workspace_domain); ptr_account = account__search(account_name);
if (!ptr_workspace) if (!ptr_account)
ptr_workspace = xmpp_workspace_alloc(workspace_domain); ptr_account = account__alloc(account_name);
if (ptr_workspace) if (ptr_account)
{ {
if (ptr_workspace->reloading_from_config if (!ptr_account->reloading_from_config++)
&& !ptr_workspace->reloaded_from_config)
{ {
for (i = 0; i < XMPP_WORKSPACE_NUM_OPTIONS; i++) for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
{ {
weechat_config_option_set( weechat_config_option_set(
ptr_workspace->options[i], NULL, 1); ptr_account->options[i], NULL, 1);
} }
ptr_workspace->reloaded_from_config = 1;
} }
ptr_account->reloading_from_config %=
ACCOUNT_NUM_OPTIONS;
rc = weechat_config_option_set( rc = weechat_config_option_set(
ptr_workspace->options[index_option], value, 1); ptr_account->options[index_option], value, 1);
} }
else else
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: error adding workspace \"%s\""), _("%s%s: error adding account \"%s\""),
weechat_prefix("error"), XMPP_PLUGIN_NAME, weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
workspace_domain); account_name);
} }
} }
free(workspace_domain); free(account_name);
} }
} }
} }
@ -188,18 +235,18 @@ int xmpp_config_workspace_read_cb (const void *pointer, void *data,
{ {
weechat_printf( weechat_printf(
NULL, NULL,
_("%s%s: error creating workspace option \"%s\""), _("%s%s: error creating account option \"%s\""),
weechat_prefix("error"), XMPP_PLUGIN_NAME, option_name); weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, option_name);
} }
return rc; return rc;
} }
int xmpp_config_workspace_write_cb (const void *pointer, void *data, int config__account_write_cb (const void *pointer, void *data,
struct t_config_file *config_file, struct t_config_file *config_file,
const char *section_name) const char *section_name)
{ {
struct t_xmpp_workspace *ptr_workspace; struct t_account *ptr_account;
int i; int i;
(void) pointer; (void) pointer;
@ -208,47 +255,45 @@ int xmpp_config_workspace_write_cb (const void *pointer, void *data,
if (!weechat_config_write_line(config_file, section_name, NULL)) if (!weechat_config_write_line(config_file, section_name, NULL))
return WEECHAT_CONFIG_WRITE_ERROR; return WEECHAT_CONFIG_WRITE_ERROR;
for (ptr_workspace = xmpp_workspaces; ptr_workspace; for (ptr_account = accounts; ptr_account;
ptr_workspace = ptr_workspace->next_workspace) ptr_account = ptr_account->next_account)
{ {
for (i = 0; i < XMPP_WORKSPACE_NUM_OPTIONS; i++) for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
{ {
if (!weechat_config_write_option(config_file, if (!weechat_config_write_option(config_file,
ptr_workspace->options[i])) ptr_account->options[i]))
return WEECHAT_CONFIG_WRITE_ERROR; return WEECHAT_CONFIG_WRITE_ERROR;
} }
} }
return WEECHAT_CONFIG_WRITE_OK; return WEECHAT_CONFIG_WRITE_OK;
} }
*/
int xmpp_config_reload (const void *pointer, void *data, int config__reload (const void *pointer, void *data,
struct t_config_file *config_file) struct t_config_file *config_file)
{ {
(void) pointer; (void) pointer;
(void) data; (void) data;
//weechat_config_section_free_options(xmpp_config_section_workspace_default); weechat_config_section_free_options(config_section_account_default);
//weechat_config_section_free_options(xmpp_config_section_workspace); weechat_config_section_free_options(config_section_account);
//xmpp_workspace_free_all(); account__free_all();
return weechat_config_reload(config_file); return weechat_config_reload(config_file);
} }
int xmpp_config_init() int config__init()
{ {
struct t_config_section *ptr_section_server; struct t_config_section *ptr_section;
struct t_config_section *ptr_section_look;
xmpp_config_file = weechat_config_new(WEECHAT_XMPP_CONFIG_NAME, config_file = weechat_config_new(WEECHAT_XMPP_CONFIG_NAME,
&xmpp_config_reload, NULL, NULL); &config__reload, NULL, NULL);
if(!xmpp_config_file) if(!config_file)
return 0; return 0;
ptr_section_server = weechat_config_new_section( ptr_section = weechat_config_new_section(
xmpp_config_file, "server", config_file, "look",
0, 0, 0, 0,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
@ -256,8 +301,24 @@ int xmpp_config_init()
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL); NULL, NULL, NULL);
ptr_section_look = weechat_config_new_section( if (!ptr_section)
xmpp_config_file, "look", {
weechat_config_free(config_file);
config_file = NULL;
return 0;
}
config_look_nick_completion_smart = weechat_config_new_option (
config_file, ptr_section,
"nick_completion_smart", "integer",
N_("smart completion for nicks (completes first with last speakers): "
"speakers = all speakers (including highlights), "
"speakers_highlights = only speakers with highlight"),
"off|speakers|speakers_highlights", 0, 0, "speakers", NULL, 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
ptr_section = weechat_config_new_section(
config_file, "account_default",
0, 0, 0, 0,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
@ -265,93 +326,52 @@ int xmpp_config_init()
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL); NULL, NULL, NULL);
if (!ptr_section_server if (!ptr_section)
|| !ptr_section_server
|| !ptr_section_look)
{ {
weechat_config_free(xmpp_config_file); weechat_config_free(config_file);
xmpp_config_file = NULL; config_file = NULL;
return 0; return 0;
} }
xmpp_config_server_jid = weechat_config_new_option ( config_section_account_default = ptr_section;
xmpp_config_file, ptr_section_server,
"jid", "string",
N_("XMPP Server JID"),
NULL, 0, 0, "", "", 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
xmpp_config_server_password = weechat_config_new_option ( config__account_create_default_options(ptr_section);
xmpp_config_file, ptr_section_server,
"password", "string",
N_("XMPP Server Password"),
NULL, 0, 0, "", "", 0,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
xmpp_config_look_nick_completion_smart = weechat_config_new_option ( ptr_section = weechat_config_new_section(
xmpp_config_file, ptr_section_look, config_file, "account",
"nick_completion_smart", "integer", 0, 0,
N_("smart completion for nicks (completes first with last speakers): " &config__account_read_cb, NULL, NULL,
"speakers = all speakers (including highlights), " &config__account_write_cb, NULL, NULL,
"speakers_highlights = only speakers with highlight"), NULL, NULL, NULL,
"off|speakers|speakers_highlights", 0, 0, "speakers", NULL, 0, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free(config_file);
config_file = NULL;
return 0;
}
//ptr_section = weechat_config_new_section( config_section_account = ptr_section;
// xmpp_config_file, "workspace_default",
// 0, 0,
// NULL, NULL, NULL,
// NULL, NULL, NULL,
// NULL, NULL, NULL,
// NULL, NULL, NULL,
// NULL, NULL, NULL);
//if (!ptr_section)
//{
// weechat_config_free(xmpp_config_file);
// xmpp_config_file = NULL;
// return 0;
//}
//xmpp_config_section_workspace_default = ptr_section;
//xmpp_config_workspace_create_default_options(ptr_section);
// ptr_section = weechat_config_new_section(
// xmpp_config_file, "workspace",
// 0, 0,
// &xmpp_config_workspace_read_cb, NULL, NULL,
// &xmpp_config_workspace_write_cb, NULL, NULL,
// NULL, NULL, NULL,
// NULL, NULL, NULL,
// NULL, NULL, NULL);
//if (!ptr_section)
//{
// weechat_config_free(xmpp_config_file);
// xmpp_config_file = NULL;
// return 0;
//}
//xmpp_config_section_workspace = ptr_section;
return 1; return 1;
} }
int xmpp_config_read() int config__read()
{ {
int rc; int rc;
rc = weechat_config_read(xmpp_config_file); rc = weechat_config_read(config_file);
return rc; return rc;
} }
int xmpp_config_write() int config__write()
{ {
return weechat_config_write(xmpp_config_file); return weechat_config_write(config_file);
} }
void xmpp_config_free() void config__free()
{ {
} }

@ -7,53 +7,51 @@
#define WEECHAT_XMPP_CONFIG_NAME "xmpp" #define WEECHAT_XMPP_CONFIG_NAME "xmpp"
enum t_xmpp_config_nick_completion enum t_config_nick_completion
{ {
XMPP_CONFIG_NICK_COMPLETION_SMART_OFF = 0, CONFIG_NICK_COMPLETION_SMART_OFF = 0,
XMPP_CONFIG_NICK_COMPLETION_SMART_SPEAKERS, CONFIG_NICK_COMPLETION_SMART_SPEAKERS,
XMPP_CONFIG_NICK_COMPLETION_SMART_SPEAKERS_HIGHLIGHTS, CONFIG_NICK_COMPLETION_SMART_SPEAKERS_HIGHLIGHTS,
}; };
extern struct t_config_file *xmpp_config_file; extern struct t_config_file *config_file;
//extern struct t_config_section *xmpp_config_section_workspace_default; extern struct t_config_section *config_section_account_default;
//extern struct t_config_section *xmpp_config_section_workspace; extern struct t_config_section *config_section_account;
extern struct t_config_option *xmpp_config_server_jid; extern struct t_config_option *config_look_nick_completion_smart;
extern struct t_config_option *xmpp_config_server_password;
extern struct t_config_option *xmpp_config_look_nick_completion_smart; extern struct t_config_option *config_account_default[];
//extern struct t_config_option *xmpp_config_workspace_default[]; int config__account_check_value_cb(const void *pointer, void *data,
struct t_config_option *option,
//int xmpp_config_workspace_check_value_cb(const void *pointer, void *data, const char *value);
// struct t_config_option *option,
// const char *value); void config__account_change_cb(const void *pointer, void *data,
struct t_config_option *option);
//void xmpp_config_workspace_change_cb(const void *pointer, void *data,
// struct t_config_option *option); struct t_config_option *config__account_new_option (struct t_config_file *config_file,
struct t_config_section *section,
//struct t_config_option *xmpp_config_workspace_new_option (struct t_config_file *config_file, int index_option,
// struct t_config_section *section, const char *option_name,
// int index_option, const char *default_value,
// const char *option_name, const char *value,
// const char *default_value, int null_value_allowed,
// const char *value, int (*callback_check_value)(const void *pointer,
// int null_value_allowed, void *data,
// int (*callback_check_value)(const void *pointer, struct t_config_option *option,
// void *data, const char *value),
// struct t_config_option *option, const void *callback_check_value_pointer,
// const char *value), void *callback_check_value_data,
// const void *callback_check_value_pointer, void (*callback_change)(const void *pointer,
// void *callback_check_value_data, void *data,
// void (*callback_change)(const void *pointer, struct t_config_option *option),
// void *data, const void *callback_change_pointer,
// struct t_config_option *option), void *callback_change_data);
// const void *callback_change_pointer,
// void *callback_change_data); extern int config__init();
extern int config__read();
extern int xmpp_config_init(); extern int config__write();
extern int xmpp_config_read(); extern void config__free();
extern int xmpp_config_write();
extern void xmpp_config_free();
#endif /*WEECHAT_XMPP_CONFIG_H*/ #endif /*WEECHAT_XMPP_CONFIG_H*/

@ -15,42 +15,13 @@
//#include "api/xmpp-api-message.h" //#include "api/xmpp-api-message.h"
//#include "api/xmpp-api-user-typing.h" //#include "api/xmpp-api-user-typing.h"
xmpp_conn_t *xmpp_connection; xmpp_conn_t *connection;
void xmpp_log_emit_weechat(void *const userdata, const xmpp_log_level_t level, const char *const area, const char *const msg) void connection__init()
{
(void) userdata;
static const char *log_level_name[4] = {"debug", "info", "warn", "error"};
time_t date = time(NULL);
const char *timestamp = weechat_util_get_time_string(&date);
weechat_printf(
NULL,
_("%s%s/%s (%s): %s"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, area,
log_level_name[level], msg);
}
xmpp_log_t xmpp_logger = {
&xmpp_log_emit_weechat,
NULL
};
void xmpp_connection_init()
{ {
xmpp_initialize(); xmpp_initialize();
} }
int xmpp_connection_autoconnect(const void *pointer, void *data, int remaining_calls)
{
xmpp_connection_connect(weechat_config_string(xmpp_config_server_jid),
weechat_config_string(xmpp_config_server_password));
return WEECHAT_RC_OK;
}
int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) int version_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
xmpp_stanza_t *reply, *query, *name, *version, *text; xmpp_stanza_t *reply, *query, *name, *version, *text;
@ -142,7 +113,7 @@ int message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
return 1; return 1;
} }
void xmpp_connection_on_connected(xmpp_conn_t *conn, xmpp_conn_event_t status, void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
int error, xmpp_stream_error_t *stream_error, int error, xmpp_stream_error_t *stream_error,
void *userdata) void *userdata)
{ {
@ -168,97 +139,60 @@ void xmpp_connection_on_connected(xmpp_conn_t *conn, xmpp_conn_event_t status,
} }
} }
void xmpp_connection_connect(const char* jid, const char* password) int connection__connect(xmpp_ctx_t *context, xmpp_conn_t **connection,
xmpp_log_t *logger, const char* jid,
const char* password, int tls)
{ {
xmpp_ctx_t *xmpp_context = xmpp_ctx_new(NULL, &xmpp_logger); *connection = xmpp_conn_new(context);
xmpp_conn_set_jid(*connection, jid);
xmpp_connection = xmpp_conn_new(xmpp_context); xmpp_conn_set_pass(*connection, password);
xmpp_conn_set_jid(xmpp_connection, jid);
xmpp_conn_set_pass(xmpp_connection, password);
auto flags = xmpp_conn_get_flags(xmpp_connection);
//flags |= XMPP_CONN_FLAG_TRUST_TLS;
xmpp_conn_set_flags(xmpp_connection, flags);
xmpp_connect_client(xmpp_connection, NULL, 0, xmpp_connection_on_connected, xmpp_context);
//struct lws_context_creation_info ctxinfo;
//struct lws_client_connect_info ccinfo;
//const char *url_protocol, *url_path;
//char path[512];
//memset(&ctxinfo, 0, sizeof(ctxinfo));
//memset(&ccinfo, 0, sizeof(ccinfo));
//ccinfo.port = 443;
//if (lws_parse_uri(workspace->ws_url,
// &url_protocol, &ccinfo.address,
// &ccinfo.port, &url_path))
//{
// weechat_printf(
// workspace->buffer,
// _("%s%s: error connecting to xmpp: bad websocket uri"),
// weechat_prefix("error"), XMPP_PLUGIN_NAME);
// return;
//}
//path[0] = '/';
//strncpy(path + 1, url_path, sizeof(path) - 2);
//path[sizeof(path) - 1] = '\0';
//ccinfo.path = path;
//ctxinfo.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; auto flags = xmpp_conn_get_flags(*connection);
//ctxinfo.port = CONTEXT_PORT_NO_LISTEN; switch (tls)
//ctxinfo.protocols = protocols; {
//ctxinfo.uid = -1; case 0:
//ctxinfo.gid = -1; flags |= XMPP_CONN_FLAG_DISABLE_TLS;
break;
//workspace->context = lws_create_context(&ctxinfo); case 1:
//if (!workspace->context) break;
//{ case 2:
// weechat_printf( flags |= XMPP_CONN_FLAG_TRUST_TLS;
// workspace->buffer, break;
// _("%s%s: error connecting to xmpp: lws init failed"), default:
// weechat_prefix("error"), XMPP_PLUGIN_NAME); break;
// return; }
//} xmpp_conn_set_flags(*connection, flags);
//else
//{
// weechat_printf(
// workspace->buffer,
// _("%s%s: connecting to %s://%s:%d%s"),
// weechat_prefix("network"), XMPP_PLUGIN_NAME,
// url_protocol, ccinfo.address, ccinfo.port, path);
//}
//ccinfo.context = workspace->context; if (xmpp_connect_client(*connection, NULL, 0, &connection__handler, context)
//ccinfo.ssl_connection = LCCSCF_USE_SSL; != XMPP_EOK)
//ccinfo.host = ccinfo.address; {
//ccinfo.origin = ccinfo.address; weechat_printf(
//ccinfo.ietf_version_or_minus_one = -1; NULL,
//ccinfo.protocol = protocols[0].name; _("%s%s: error connecting to %s"),
//ccinfo.pwsi = &workspace->client_wsi; weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
//ccinfo.userdata = workspace; jid);
return 0;
}
//lws_client_connect_via_info(&ccinfo); weechat_printf(
NULL,
_("%s%s: c'necting to %s"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
jid);
return 1;
} }
int xmpp_connection_check_events(const void *pointer, void *data, int remaining_calls) void connection__process(xmpp_ctx_t *context, xmpp_conn_t *connection,
const unsigned long timeout)
{ {
(void) pointer; if (connection)
(void) data;
(void) remaining_calls;
if (xmpp_connection)
{ {
xmpp_ctx_t *xmpp_context = xmpp_conn_get_context(xmpp_connection); xmpp_run_once(context ? context : xmpp_conn_get_context(connection),
timeout);
xmpp_run_once(xmpp_context, 10);
} }
return WEECHAT_RC_OK;
} }
int xmpp_connection_route_message(xmpp_conn_t *workspace, int connection__route_message(xmpp_conn_t *workspace,
const char *type, void *message) const char *type, void *message)
{ {
//struct stringcase key; //struct stringcase key;

@ -5,17 +5,16 @@
#ifndef _WEECHAT_XMPP_CONNECTION_H_ #ifndef _WEECHAT_XMPP_CONNECTION_H_
#define _WEECHAT_XMPP_CONNECTION_H_ #define _WEECHAT_XMPP_CONNECTION_H_
extern xmpp_conn_t *xmpp_connection; void connection__init();
void xmpp_connection_init(); int connection__connect(xmpp_ctx_t *context, xmpp_conn_t **connection,
xmpp_log_t *logger, const char* jid,
const char* password, int tls);
int xmpp_connection_autoconnect(const void *pointer, void *data, int remaining_calls); void connection__process(xmpp_ctx_t *context, xmpp_conn_t *connection,
const unsigned long timeout);
void xmpp_connection_connect(const char* jid, const char* password); int connection__route_message(xmpp_conn_t *connection,
int xmpp_connection_check_events(const void *pointer, void *data, int remaining_calls);
int xmpp_connection_route_message(xmpp_conn_t *connection,
const char *type, void *message); const char *type, void *message);
#endif /*WEECHAT_XMPP_CONNECTION_H*/ #endif /*WEECHAT_XMPP_CONNECTION_H*/

@ -0,0 +1,64 @@
// 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 <strophe.h>
#include <stdlib.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "account.h"
#include "channel.h"
#include "buffer.h"
//#include "request.h"
#include "message.h"
#include "input.h"
int input__data(struct t_gui_buffer *buffer, const char *text)
{
struct t_account *account = NULL;
struct t_channel *channel = NULL;
struct t_request *request;
buffer__get_account_and_channel(buffer, &account, &channel);
if (!account)
return WEECHAT_RC_ERROR;
if (channel)
{
if (!account->is_connected)
{
weechat_printf(buffer,
_("%s%s: you are not connected to server"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
return WEECHAT_RC_OK;
}
//TODO: SEND
//request = request_chat_postmessage(account,
// weechat_config_string(
// account->options[ACCOUNT_OPTION_TOKEN]),
// channel->id, text);
//if (request)
// account__register_request(account, request);
}
else
{
weechat_printf(buffer,
_("%s%s: this buffer is not a channel!"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
}
return WEECHAT_RC_OK;
}
int input__data_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *text)
{
(void) pointer;
(void) data;
return input__data(buffer, text);
}

@ -0,0 +1,12 @@
// 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 _WEECHAT_XMPP_INPUT_H_
#define _WEECHAT_XMPP_INPUT_H_
int input__data_cb(const void *pointer, void *data,
struct t_gui_buffer *buffer,
const char *input_data);
#endif /*WEECHAT_XMPP_INPUT_H*/

@ -0,0 +1,249 @@
// 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 <strophe.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <regex.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "account.h"
#include "channel.h"
#include "user.h"
#include "message.h"
static const char format_regex[] = "<([^>]*?)>";
static const size_t max_groups = 2;
char *message__translate_code(struct t_account *account,
const char *code)
{
struct t_channel *channel;
struct t_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 = channel__search(account, 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 = user__search(account, 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 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 *message__decode(struct t_account *account,
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(
account->buffer,
_("%s%s: error compiling message formatting regex: %s"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME,
msgbuf);
return strdup(text);
}
decoded_text = malloc(MESSAGE_MAX_LENGTH);
if (!decoded_text)
{
regfree(&reg);
weechat_printf(
account->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), WEECHAT_XMPP_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(
account->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), WEECHAT_XMPP_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(
account->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), WEECHAT_XMPP_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(
account->buffer,
_("%s%s: error allocating space for message"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
return strdup(text);
}
free(copy);
strncat(decoded_text, prematch,
MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
free(prematch);
char *replacement = message__translate_code(account, match);
free(match);
strncat(decoded_text, replacement,
MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
free(replacement);
}
strncat(decoded_text, cursor,
MESSAGE_MAX_LENGTH - strlen(decoded_text) - 1);
message__htmldecode(decoded_text, decoded_text,
MESSAGE_MAX_LENGTH);
regfree(&reg);
return decoded_text;
}

@ -0,0 +1,13 @@
// 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 _WEECHAT_XMPP_MESSAGE_H_
#define _WEECHAT_XMPP_MESSAGE_H_
#define MESSAGE_MAX_LENGTH 40000
char *message__decode(struct t_account *account,
const char *text);
#endif /*WEECHAT_XMPP_MESSAGE_H*/

@ -12,13 +12,13 @@
#include "config.h" #include "config.h"
#include "connection.h" #include "connection.h"
#include "command.h" #include "command.h"
//#include "xmpp-workspace.h" #include "account.h"
//#include "xmpp-buffer.h" #include "buffer.h"
//#include "xmpp-completion.h" //#include "xmpp-completion.h"
WEECHAT_PLUGIN_NAME(WEECHAT_XMPP_PLUGIN_NAME); WEECHAT_PLUGIN_NAME(WEECHAT_XMPP_PLUGIN_NAME);
WEECHAT_PLUGIN_DESCRIPTION(N_("XMPP protocol")); WEECHAT_PLUGIN_DESCRIPTION(N_("XMPP client protocol"));
WEECHAT_PLUGIN_AUTHOR("bqv <weechat@fron.io>"); WEECHAT_PLUGIN_AUTHOR("bqv <weechat@fron.io>");
WEECHAT_PLUGIN_VERSION(WEECHAT_XMPP_PLUGIN_VERSION); WEECHAT_PLUGIN_VERSION(WEECHAT_XMPP_PLUGIN_VERSION);
WEECHAT_PLUGIN_LICENSE("MPL2"); WEECHAT_PLUGIN_LICENSE("MPL2");
@ -26,34 +26,31 @@ WEECHAT_PLUGIN_PRIORITY(5500);
struct t_weechat_plugin *weechat_xmpp_plugin = NULL; struct t_weechat_plugin *weechat_xmpp_plugin = NULL;
struct t_hook *xmpp_hook_timer = NULL; struct t_hook *weechat_xmpp_autoconnect_timer = NULL;
struct t_hook *weechat_xmpp_process_timer = NULL;
struct t_gui_bar_item *xmpp_typing_bar_item = NULL; struct t_gui_bar_item *weechat_xmpp_typing_bar_item = NULL;
int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[]) int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
{ {
(void) argc; (void) argc;
(void) argv; (void) argv;
weechat_plugin = plugin; weechat_xmpp_plugin = plugin;
if (!xmpp_config_init()) if (!config__init())
return WEECHAT_RC_ERROR; return WEECHAT_RC_ERROR;
xmpp_config_read(); config__read();
xmpp_connection_init(); connection__init();
xmpp_command_init(); command__init();
//xmpp_completion_init(); //completion__init();
xmpp_hook_timer = weechat_hook_timer(1 * 1000, 0, 1, weechat_xmpp_process_timer = weechat_hook_timer(0.1 * 1000, 0, 0,
&xmpp_connection_autoconnect, &account__timer_cb,
NULL, NULL);
xmpp_hook_timer = weechat_hook_timer(0.1 * 1000, 0, 0,
&xmpp_connection_check_events,
NULL, NULL); NULL, NULL);
if (!weechat_bar_search("typing")) if (!weechat_bar_search("typing"))
@ -64,9 +61,9 @@ int weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
"off", "xmpp_typing"); "off", "xmpp_typing");
} }
//xmpp_typing_bar_item = weechat_bar_item_new("xmpp_typing", weechat_xmpp_typing_bar_item = weechat_bar_item_new("xmpp_typing",
// &xmpp_buffer_typing_bar_cb, &buffer__typing_bar_cb,
// NULL, NULL); NULL, NULL);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
@ -76,25 +73,19 @@ int weechat_plugin_end(struct t_weechat_plugin *plugin)
// make C compiler happy // make C compiler happy
(void) plugin; (void) plugin;
if (xmpp_typing_bar_item) if (weechat_xmpp_typing_bar_item)
weechat_bar_item_remove(xmpp_typing_bar_item); weechat_bar_item_remove(weechat_xmpp_typing_bar_item);
if (xmpp_hook_timer) if (weechat_xmpp_autoconnect_timer)
weechat_unhook(xmpp_hook_timer); weechat_unhook(weechat_xmpp_autoconnect_timer);
if (weechat_xmpp_process_timer)
weechat_unhook(weechat_xmpp_process_timer);
xmpp_config_write(); config__write();
if (xmpp_connection) account__disconnect_all();
{
xmpp_ctx_t *xmpp_context = xmpp_conn_get_context(xmpp_connection);
if (xmpp_conn_is_connected(xmpp_connection)) account__free_all();
xmpp_disconnect(xmpp_connection);
xmpp_conn_release(xmpp_connection);
xmpp_ctx_free(xmpp_context);
}
xmpp_shutdown(); xmpp_shutdown();

242
user.c

@ -0,0 +1,242 @@
// 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 <strophe.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "account.h"
#include "user.h"
#include "channel.h"
const char *user__get_colour(struct t_user *user)
{
return weechat_info_get("nick_color", user->profile.display_name);
}
const char *user__get_colour_for_nicklist(struct t_user *user)
{
return weechat_info_get("nick_color_name", user->profile.display_name);
}
const char *user__as_prefix(struct t_account *account,
struct t_user *user,
const char *name)
{
static char result[256];
(void) account;
snprintf(result, sizeof(result), "%s%s\t",
user__get_colour(user),
name ? name : user->profile.display_name);
return result;
}
struct t_user *user__bot_search(struct t_account *account,
const char *bot_id)
{
struct t_user *ptr_user;
if (!account || !bot_id)
return NULL;
for (ptr_user = account->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_user *user__search(struct t_account *account,
const char *id)
{
struct t_user *ptr_user;
if (!account || !id)
return NULL;
for (ptr_user = account->users; ptr_user;
ptr_user = ptr_user->next_user)
{
if (weechat_strcasecmp(ptr_user->id, id) == 0)
return ptr_user;
}
return NULL;
}
void user__nicklist_add(struct t_account *account,
struct t_channel *channel,
struct t_user *user)
{
struct t_gui_nick_group *ptr_group;
struct t_gui_buffer *ptr_buffer;
ptr_buffer = channel ? channel->buffer : account->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" :
user__get_colour_for_nicklist(user),
user->is_away ? "+" : "",
"bar_fg",
1);
}
struct t_user *user__new(struct t_account *account,
const char *id, const char *display_name)
{
struct t_user *new_user, *ptr_user;
if (!account || !id || !display_name)
{
return NULL;
}
if (!display_name[0] && strcmp("USLACKBOT", id) == 0)
return NULL;
if (!account->users)
channel__add_nicklist_groups(account, NULL);
ptr_user = user__search(account, id);
if (ptr_user)
{
user__nicklist_add(account, NULL, ptr_user);
return ptr_user;
}
if ((new_user = malloc(sizeof(*new_user))) == NULL)
{
return NULL;
}
new_user->prev_user = account->last_user;
new_user->next_user = NULL;
if (account->last_user)
(account->last_user)->next_user = new_user;
else
account->users = new_user;
account->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("xmppbot");
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;
user__nicklist_add(account, NULL, new_user);
return new_user;
}
void user__free(struct t_account *account,
struct t_user *user)
{
struct t_user *new_users;
if (!account || !user)
return;
/* remove user from users list */
if (account->last_user == user)
account->last_user = user->prev_user;
if (user->prev_user)
{
(user->prev_user)->next_user = user->next_user;
new_users = account->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);
account->users = new_users;
}
void user__free_all(struct t_account *account)
{
while (account->users)
user__free(account, account->users);
}

@ -0,0 +1,75 @@
// 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 _WEECHAT_XMPP_USER_H_
#define _WEECHAT_XMPP_USER_H_
struct t_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_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_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_user *prev_user;
struct t_user *next_user;
};
struct t_channel;
const char *user__get_colour(struct t_user *user);
const char *user__as_prefix(struct t_account *account,
struct t_user *user,
const char *name);
struct t_user *user__bot_search(struct t_account *account,
const char *bot_id);
struct t_user *user__search(struct t_account *account,
const char *id);
struct t_user *user__new(struct t_account *account,
const char *id, const char *display_name);
void user__free_all(struct t_account *account);
void user__nicklist_add(struct t_account *account,
struct t_channel *channel,
struct t_user *user);
#endif /*WEECHAT_XMPP_USER_H*/
Loading…
Cancel
Save