mirror of https://github.com/bqv/weechat-xmpp
buffers! hooray.
parent
b6b6ed6246
commit
2b42e8cd2a
@ -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*/
|
@ -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(®, format_regex, REG_EXTENDED)))
|
||||||
|
{
|
||||||
|
regerror(rc, ®, 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(®);
|
||||||
|
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(®, cursor, max_groups, groups, 0) == 0; cursor += offset)
|
||||||
|
{
|
||||||
|
offset = groups[0].rm_eo;
|
||||||
|
|
||||||
|
char *copy = strdup(cursor);
|
||||||
|
if (!copy)
|
||||||
|
{
|
||||||
|
regfree(®);
|
||||||
|
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(®);
|
||||||
|
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(®);
|
||||||
|
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(®);
|
||||||
|
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*/
|
@ -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…
Reference in New Issue