|
|
|
@ -8,6 +8,7 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <fmt/core.h>
|
|
|
|
|
#include <libxml/xmlwriter.h>
|
|
|
|
|
#include <weechat/weechat-plugin.h>
|
|
|
|
|
|
|
|
|
@ -22,291 +23,12 @@
|
|
|
|
|
#include "channel.hh"
|
|
|
|
|
#include "buffer.hh"
|
|
|
|
|
|
|
|
|
|
std::unordered_map<std::string, struct t_account *> accounts;
|
|
|
|
|
|
|
|
|
|
char *account_options[ACCOUNT_NUM_OPTIONS][2] =
|
|
|
|
|
{ { (char*)"jid", (char*)"" },
|
|
|
|
|
{ (char*)"password", (char*)"" },
|
|
|
|
|
{ (char*)"tls", (char*)"normal" },
|
|
|
|
|
{ (char*)"nickname", (char*)"" },
|
|
|
|
|
{ (char*)"autoconnect", (char*)"" },
|
|
|
|
|
{ (char*)"resource", (char*)"" },
|
|
|
|
|
{ (char*)"status", (char*)"probably about to segfault" },
|
|
|
|
|
{ (char*)"pgp_path", (char*)"" },
|
|
|
|
|
{ (char*)"pgp_keyid", (char*)"" },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct t_account *account__search(const char *name)
|
|
|
|
|
{
|
|
|
|
|
if (!name)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
auto ptr_account = accounts.find(name);
|
|
|
|
|
if (ptr_account != accounts.end())
|
|
|
|
|
{
|
|
|
|
|
return ptr_account->second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* account not found */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct t_account *account__casesearch(const char *name)
|
|
|
|
|
{
|
|
|
|
|
if (!name)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (auto ptr_account : accounts)
|
|
|
|
|
{
|
|
|
|
|
if (weechat_strcasecmp(ptr_account.second->name, name) == 0)
|
|
|
|
|
return ptr_account.second;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct t_account_device *account__search_device(struct t_account *account, uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
struct t_account_device *ptr_device;
|
|
|
|
|
|
|
|
|
|
if (!account)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (ptr_device = account->devices; ptr_device;
|
|
|
|
|
ptr_device = ptr_device->next_device)
|
|
|
|
|
{
|
|
|
|
|
if (ptr_device->id == id)
|
|
|
|
|
return ptr_device;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__add_device(struct t_account *account,
|
|
|
|
|
struct t_account_device *device)
|
|
|
|
|
{
|
|
|
|
|
struct t_account_device *new_device;
|
|
|
|
|
|
|
|
|
|
new_device = account__search_device(account, device->id);
|
|
|
|
|
if (!new_device)
|
|
|
|
|
{
|
|
|
|
|
new_device = new struct t_account_device;
|
|
|
|
|
new_device->id = device->id;
|
|
|
|
|
new_device->name = strdup(device->name);
|
|
|
|
|
new_device->label = device->label ? strdup(device->label) : NULL;
|
|
|
|
|
|
|
|
|
|
new_device->prev_device = account->last_device;
|
|
|
|
|
new_device->next_device = NULL;
|
|
|
|
|
if (account->last_device)
|
|
|
|
|
(account->last_device)->next_device = new_device;
|
|
|
|
|
else
|
|
|
|
|
account->devices = new_device;
|
|
|
|
|
account->last_device = new_device;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__free_device(struct t_account *account, struct t_account_device *device)
|
|
|
|
|
{
|
|
|
|
|
struct t_account_device *new_devices;
|
|
|
|
|
|
|
|
|
|
if (!account || !device)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* remove device from devices list */
|
|
|
|
|
if (account->last_device == device)
|
|
|
|
|
account->last_device = device->prev_device;
|
|
|
|
|
if (device->prev_device)
|
|
|
|
|
{
|
|
|
|
|
(device->prev_device)->next_device = device->next_device;
|
|
|
|
|
new_devices = account->devices;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
new_devices = device->next_device;
|
|
|
|
|
|
|
|
|
|
if (device->next_device)
|
|
|
|
|
(device->next_device)->prev_device = device->prev_device;
|
|
|
|
|
|
|
|
|
|
/* free device data */
|
|
|
|
|
if (device->label)
|
|
|
|
|
free(device->label);
|
|
|
|
|
if (device->name)
|
|
|
|
|
free(device->name);
|
|
|
|
|
|
|
|
|
|
delete device;
|
|
|
|
|
|
|
|
|
|
account->devices = new_devices;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__free_device_all(struct t_account *account)
|
|
|
|
|
{
|
|
|
|
|
while (account->devices)
|
|
|
|
|
account__free_device(account, account->devices);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xmpp_stanza_t *account__get_devicelist(struct t_account *account)
|
|
|
|
|
{
|
|
|
|
|
xmpp_stanza_t *parent, **children;
|
|
|
|
|
struct t_account_device *device;
|
|
|
|
|
const char *ns, *node;
|
|
|
|
|
char id[64] = {0};
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
device = new struct t_account_device;
|
|
|
|
|
|
|
|
|
|
device->id = account->omemo.device_id;
|
|
|
|
|
snprintf(id, sizeof(id), "%u", device->id);
|
|
|
|
|
device->name = strdup(id);
|
|
|
|
|
device->label = strdup("weechat");
|
|
|
|
|
|
|
|
|
|
children = (xmpp_stanza_t **)malloc(sizeof(xmpp_stanza_t *) * 128);
|
|
|
|
|
children[i++] = stanza__iq_pubsub_publish_item_list_device(
|
|
|
|
|
account->context, NULL, with_noop(device->name), NULL);
|
|
|
|
|
|
|
|
|
|
free(device->label);
|
|
|
|
|
free(device->name);
|
|
|
|
|
delete device;
|
|
|
|
|
|
|
|
|
|
for (device = account->devices; device;
|
|
|
|
|
device = device->next_device)
|
|
|
|
|
{
|
|
|
|
|
if (device->id != account->omemo.device_id)
|
|
|
|
|
children[i++] = stanza__iq_pubsub_publish_item_list_device(
|
|
|
|
|
account->context, NULL, with_noop(device->name), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
children[i] = NULL;
|
|
|
|
|
node = "eu.siacs.conversations.axolotl";
|
|
|
|
|
children[0] = stanza__iq_pubsub_publish_item_list(
|
|
|
|
|
account->context, NULL, children, with_noop(node));
|
|
|
|
|
children[1] = NULL;
|
|
|
|
|
children[0] = stanza__iq_pubsub_publish_item(
|
|
|
|
|
account->context, NULL, children, with_noop("current"));
|
|
|
|
|
node = "eu.siacs.conversations.axolotl.devicelist";
|
|
|
|
|
children[0] = stanza__iq_pubsub_publish(account->context,
|
|
|
|
|
NULL, children,
|
|
|
|
|
with_noop(node));
|
|
|
|
|
ns = "http://jabber.org/protocol/pubsub";
|
|
|
|
|
children[0] = stanza__iq_pubsub(account->context, NULL,
|
|
|
|
|
children, with_noop(ns));
|
|
|
|
|
parent = stanza__iq(account->context, NULL,
|
|
|
|
|
children, NULL, strdup("announce1"),
|
|
|
|
|
NULL, NULL, strdup("set"));
|
|
|
|
|
free(children);
|
|
|
|
|
|
|
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct t_account_mam_query *account__add_mam_query(struct t_account *account,
|
|
|
|
|
struct t_channel *channel,
|
|
|
|
|
const char *id,
|
|
|
|
|
time_t *start, time_t *end)
|
|
|
|
|
{
|
|
|
|
|
struct t_account_mam_query *mam_query;
|
|
|
|
|
|
|
|
|
|
if (!(mam_query = account__mam_query_search(account, id)))
|
|
|
|
|
{
|
|
|
|
|
mam_query = (struct t_account_mam_query*)malloc(sizeof(struct t_account_mam_query));
|
|
|
|
|
mam_query->id = strdup(id);
|
|
|
|
|
mam_query->with = strdup(channel->id);
|
|
|
|
|
|
|
|
|
|
mam_query->has_start = start != NULL;
|
|
|
|
|
if (mam_query->has_start)
|
|
|
|
|
mam_query->start = *start;
|
|
|
|
|
mam_query->has_end = end != NULL;
|
|
|
|
|
if (mam_query->has_end)
|
|
|
|
|
mam_query->end = *end;
|
|
|
|
|
|
|
|
|
|
mam_query->prev_mam_query = account->last_mam_query;
|
|
|
|
|
mam_query->next_mam_query = NULL;
|
|
|
|
|
if (account->last_mam_query)
|
|
|
|
|
(account->last_mam_query)->next_mam_query = mam_query;
|
|
|
|
|
else
|
|
|
|
|
account->mam_queries = mam_query;
|
|
|
|
|
account->last_mam_query = mam_query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mam_query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct t_account_mam_query *account__mam_query_search(struct t_account *account,
|
|
|
|
|
const char *id)
|
|
|
|
|
{
|
|
|
|
|
struct t_account_mam_query *ptr_mam_query;
|
|
|
|
|
|
|
|
|
|
if (!account || !id)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (ptr_mam_query = account->mam_queries; ptr_mam_query;
|
|
|
|
|
ptr_mam_query = ptr_mam_query->next_mam_query)
|
|
|
|
|
{
|
|
|
|
|
if (weechat_strcasecmp(ptr_mam_query->id, id) == 0)
|
|
|
|
|
return ptr_mam_query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
std::unordered_map<std::string, weechat::account> weechat::accounts;
|
|
|
|
|
|
|
|
|
|
void account__mam_query_free(struct t_account *account,
|
|
|
|
|
struct t_account_mam_query *mam_query)
|
|
|
|
|
{
|
|
|
|
|
struct t_account_mam_query *new_mam_queries;
|
|
|
|
|
|
|
|
|
|
if (!account || !mam_query)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* remove mam_query from mam_queries list */
|
|
|
|
|
if (account->last_mam_query == mam_query)
|
|
|
|
|
account->last_mam_query = mam_query->prev_mam_query;
|
|
|
|
|
if (mam_query->prev_mam_query)
|
|
|
|
|
{
|
|
|
|
|
(mam_query->prev_mam_query)->next_mam_query = mam_query->next_mam_query;
|
|
|
|
|
new_mam_queries = account->mam_queries;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
new_mam_queries = mam_query->next_mam_query;
|
|
|
|
|
|
|
|
|
|
if (mam_query->next_mam_query)
|
|
|
|
|
(mam_query->next_mam_query)->prev_mam_query = mam_query->prev_mam_query;
|
|
|
|
|
|
|
|
|
|
/* free mam_query data */
|
|
|
|
|
if (mam_query->id)
|
|
|
|
|
free(mam_query->id);
|
|
|
|
|
if (mam_query->with)
|
|
|
|
|
free(mam_query->with);
|
|
|
|
|
|
|
|
|
|
free(mam_query);
|
|
|
|
|
|
|
|
|
|
account->mam_queries = new_mam_queries;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__mam_query_free_all(struct t_account *account)
|
|
|
|
|
{
|
|
|
|
|
while (account->mam_queries)
|
|
|
|
|
account__mam_query_free(account, account->mam_queries);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__log_emit_weechat(void *const userdata, const xmpp_log_level_t level,
|
|
|
|
|
void weechat::log_emit(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;
|
|
|
|
|
auto account = static_cast<weechat::account*>(userdata);
|
|
|
|
|
|
|
|
|
|
static const char *log_level_name[4] = {"debug", "info", "warn", "error"};
|
|
|
|
|
|
|
|
|
@ -389,331 +111,338 @@ void account__log_emit_weechat(void *const userdata, const xmpp_log_level_t leve
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct t_account *account__alloc(const char *name)
|
|
|
|
|
bool weechat::account::search(weechat::account* &out,
|
|
|
|
|
const std::string name, bool casesensitive)
|
|
|
|
|
{
|
|
|
|
|
struct t_account *new_account;
|
|
|
|
|
int i, length;
|
|
|
|
|
char *option_name;
|
|
|
|
|
if (name.empty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (account__casesearch(name))
|
|
|
|
|
return NULL;
|
|
|
|
|
if (casesensitive)
|
|
|
|
|
{
|
|
|
|
|
for (auto& account : weechat::accounts)
|
|
|
|
|
{
|
|
|
|
|
if (weechat_strcasecmp(account.second.name.data(), name.data()) == 0)
|
|
|
|
|
{
|
|
|
|
|
out = &account.second;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (auto account = accounts.find(name); account != accounts.end())
|
|
|
|
|
{
|
|
|
|
|
out = &account->second;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* alloc memory for new account */
|
|
|
|
|
new_account = new struct t_account;
|
|
|
|
|
std::memset(&new_account->omemo, 0, sizeof(new_account->omemo));
|
|
|
|
|
if (!new_account)
|
|
|
|
|
(void) out;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool weechat::account::search_device(weechat::account::device* out, std::uint32_t id)
|
|
|
|
|
{
|
|
|
|
|
if (id == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (auto device = devices.find(id); device != devices.end())
|
|
|
|
|
{
|
|
|
|
|
weechat_printf(NULL,
|
|
|
|
|
_("%s%s: error when allocating new account"),
|
|
|
|
|
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
|
|
|
|
|
out = &device->second;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(void) out;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void weechat::account::add_device(weechat::account::device *device)
|
|
|
|
|
{
|
|
|
|
|
if (!devices.contains(device->id))
|
|
|
|
|
{
|
|
|
|
|
devices[device->id].id = device->id;
|
|
|
|
|
devices[device->id].name = device->name;
|
|
|
|
|
devices[device->id].label = device->label;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accounts[name] = new_account;
|
|
|
|
|
void weechat::account::device_free_all()
|
|
|
|
|
{
|
|
|
|
|
devices.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set name */
|
|
|
|
|
new_account->name = strdup(name);
|
|
|
|
|
xmpp_stanza_t *weechat::account::get_devicelist()
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
/* internal vars */
|
|
|
|
|
new_account->reloading_from_config = 0;
|
|
|
|
|
account::device device;
|
|
|
|
|
|
|
|
|
|
new_account->is_connected = 0;
|
|
|
|
|
new_account->disconnected = 0;
|
|
|
|
|
device.id = omemo.device_id;
|
|
|
|
|
device.name = fmt::format("%u", device.id);
|
|
|
|
|
device.label = "weechat";
|
|
|
|
|
|
|
|
|
|
new_account->current_retry = 0;
|
|
|
|
|
new_account->reconnect_delay = 0;
|
|
|
|
|
new_account->reconnect_start = 0;
|
|
|
|
|
auto children = (xmpp_stanza_t **)malloc(sizeof(xmpp_stanza_t *) * 128);
|
|
|
|
|
children[i++] = stanza__iq_pubsub_publish_item_list_device(
|
|
|
|
|
context, NULL, with_noop(device.name.data()), NULL);
|
|
|
|
|
|
|
|
|
|
new_account->logger.handler = &account__log_emit_weechat;
|
|
|
|
|
new_account->logger.userdata = new_account;
|
|
|
|
|
new_account->memory.alloc = [](const size_t size, void *const) {
|
|
|
|
|
return calloc(1, size);
|
|
|
|
|
};
|
|
|
|
|
new_account->memory.free = [](void *ptr, void *const) {
|
|
|
|
|
free(ptr);
|
|
|
|
|
};
|
|
|
|
|
new_account->memory.realloc = [](void *ptr, const size_t size, void *const) {
|
|
|
|
|
return realloc(ptr, size);
|
|
|
|
|
};
|
|
|
|
|
new_account->memory.userdata = new_account;
|
|
|
|
|
new_account->context = xmpp_ctx_new(&new_account->memory, &new_account->logger);
|
|
|
|
|
new_account->connection = NULL;
|
|
|
|
|
|
|
|
|
|
new_account->buffer = NULL;
|
|
|
|
|
new_account->buffer_as_string = NULL;
|
|
|
|
|
|
|
|
|
|
new_account->devices = NULL;
|
|
|
|
|
new_account->last_device = NULL;
|
|
|
|
|
new_account->mam_queries = NULL;
|
|
|
|
|
new_account->last_mam_query = 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++)
|
|
|
|
|
for (auto& device : devices)
|
|
|
|
|
{
|
|
|
|
|
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 = (char*)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);
|
|
|
|
|
}
|
|
|
|
|
if (device.first != omemo.device_id)
|
|
|
|
|
children[i++] = stanza__iq_pubsub_publish_item_list_device(
|
|
|
|
|
context, NULL, with_noop(device.second.name.data()), NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new_account;
|
|
|
|
|
children[i] = NULL;
|
|
|
|
|
const char *node = "eu.siacs.conversations.axolotl";
|
|
|
|
|
children[0] = stanza__iq_pubsub_publish_item_list(
|
|
|
|
|
context, NULL, children, with_noop(node));
|
|
|
|
|
children[1] = NULL;
|
|
|
|
|
children[0] = stanza__iq_pubsub_publish_item(
|
|
|
|
|
context, NULL, children, with_noop("current"));
|
|
|
|
|
node = "eu.siacs.conversations.axolotl.devicelist";
|
|
|
|
|
children[0] = stanza__iq_pubsub_publish(context, NULL, children, with_noop(node));
|
|
|
|
|
const char *ns = "http://jabber.org/protocol/pubsub";
|
|
|
|
|
children[0] = stanza__iq_pubsub(context, NULL, children, with_noop(ns));
|
|
|
|
|
xmpp_stanza_t * parent = stanza__iq(context, NULL,
|
|
|
|
|
children, NULL, strdup("announce1"),
|
|
|
|
|
NULL, NULL, strdup("set"));
|
|
|
|
|
free(children);
|
|
|
|
|
|
|
|
|
|
return parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__free_data(struct t_account *account)
|
|
|
|
|
void weechat::account::add_mam_query(const std::string id, const std::string with,
|
|
|
|
|
tl::optional<time_t> start, tl::optional<time_t> end)
|
|
|
|
|
{
|
|
|
|
|
//int i;
|
|
|
|
|
if (!mam_queries.contains(id))
|
|
|
|
|
{
|
|
|
|
|
mam_queries[id].id = id;
|
|
|
|
|
mam_queries[id].with = with;
|
|
|
|
|
|
|
|
|
|
if (!account)
|
|
|
|
|
return;
|
|
|
|
|
mam_queries[id].start = start;
|
|
|
|
|
mam_queries[id].end = end;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* free linked lists */
|
|
|
|
|
/*
|
|
|
|
|
for (i = 0; i < IRC_SERVER_NUM_OUTQUEUES_PRIO; i++)
|
|
|
|
|
bool weechat::account::mam_query_search(weechat::account::mam_query* out,
|
|
|
|
|
const std::string id)
|
|
|
|
|
{
|
|
|
|
|
if (id.empty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (auto mam_query = mam_queries.find(id); mam_query != mam_queries.end())
|
|
|
|
|
{
|
|
|
|
|
account__outqueue_free_all(account, i);
|
|
|
|
|
out = &mam_query->second;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
xmpp_redirect_free_all(account);
|
|
|
|
|
xmpp_notify_free_all(account);
|
|
|
|
|
*/
|
|
|
|
|
account__free_device_all(account);
|
|
|
|
|
account__mam_query_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);
|
|
|
|
|
(void) out;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* free account data */
|
|
|
|
|
//for (i = 0; i < ACCOUNT_NUM_OPTIONS; i++)
|
|
|
|
|
//{
|
|
|
|
|
// if (account->options[i])
|
|
|
|
|
// weechat_config_option_free(account->options[i]);
|
|
|
|
|
//}
|
|
|
|
|
void weechat::account::mam_query_remove(const std::string id)
|
|
|
|
|
{
|
|
|
|
|
mam_queries.erase(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (account->name)
|
|
|
|
|
free(account->name);
|
|
|
|
|
void weechat::account::mam_query_free_all()
|
|
|
|
|
{
|
|
|
|
|
mam_queries.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (account->buffer_as_string)
|
|
|
|
|
free(account->buffer_as_string);
|
|
|
|
|
xmpp_log_t make_logger(void *userdata)
|
|
|
|
|
{
|
|
|
|
|
xmpp_log_t logger = { nullptr };
|
|
|
|
|
logger.handler = &weechat::log_emit;
|
|
|
|
|
logger.userdata = userdata;
|
|
|
|
|
return logger;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//channel__free_all(account);
|
|
|
|
|
//user__free_all(account);
|
|
|
|
|
xmpp_mem_t make_memory(void *userdata)
|
|
|
|
|
{
|
|
|
|
|
xmpp_mem_t memory = { nullptr };
|
|
|
|
|
memory.alloc = [](const size_t size, void *const) {
|
|
|
|
|
return calloc(1, size);
|
|
|
|
|
};
|
|
|
|
|
memory.free = [](void *ptr, void *const) {
|
|
|
|
|
free(ptr);
|
|
|
|
|
};
|
|
|
|
|
memory.realloc = [](void *ptr, const size_t size, void *const) {
|
|
|
|
|
return realloc(ptr, size);
|
|
|
|
|
};
|
|
|
|
|
memory.userdata = userdata;
|
|
|
|
|
return memory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__free(struct t_account *account)
|
|
|
|
|
weechat::account::account(config_file& config_file, const std::string name)
|
|
|
|
|
: name(name), memory(make_memory(this)), logger(make_logger(this))
|
|
|
|
|
, context(&memory, &logger), connection(*this, context)
|
|
|
|
|
, config_account(config_file, config_file.configuration.section_account, name.data())
|
|
|
|
|
{
|
|
|
|
|
if (!account)
|
|
|
|
|
return;
|
|
|
|
|
if (account* result = nullptr; account::search(result, name))
|
|
|
|
|
throw std::invalid_argument("account already exists");
|
|
|
|
|
|
|
|
|
|
this->jid(config_file.configuration.account_default.option_jid.string().data());
|
|
|
|
|
this->password(config_file.configuration.account_default.option_password.string().data());
|
|
|
|
|
this->tls(config_file.configuration.account_default.option_tls.string().data());
|
|
|
|
|
this->nickname(config_file.configuration.account_default.option_nickname.string().data());
|
|
|
|
|
this->autoconnect(config_file.configuration.account_default.option_autoconnect.string().data());
|
|
|
|
|
this->resource(config_file.configuration.account_default.option_resource.string().data());
|
|
|
|
|
this->status(config_file.configuration.account_default.option_status.string().data());
|
|
|
|
|
this->pgp_path(config_file.configuration.account_default.option_pgp_path.string().data());
|
|
|
|
|
this->pgp_keyid(config_file.configuration.account_default.option_pgp_keyid.string().data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
weechat::account::~account()
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* 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);
|
|
|
|
|
if (buffer)
|
|
|
|
|
weechat_buffer_close(buffer);
|
|
|
|
|
|
|
|
|
|
accounts.erase(account->name);
|
|
|
|
|
accounts.erase(name);
|
|
|
|
|
|
|
|
|
|
account__free_data(account);
|
|
|
|
|
delete account;
|
|
|
|
|
}
|
|
|
|
|
/* close xmpp context */
|
|
|
|
|
if (connection)
|
|
|
|
|
xmpp_conn_release(connection);
|
|
|
|
|
if (context)
|
|
|
|
|
xmpp_ctx_free(context);
|
|
|
|
|
|
|
|
|
|
void account__free_all()
|
|
|
|
|
{
|
|
|
|
|
for (auto account : accounts)
|
|
|
|
|
{
|
|
|
|
|
account__free(account.second);
|
|
|
|
|
}
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__disconnect(struct t_account *account, int reconnect)
|
|
|
|
|
void weechat::account::disconnect(int reconnect)
|
|
|
|
|
{
|
|
|
|
|
(void) reconnect;
|
|
|
|
|
|
|
|
|
|
struct t_channel *ptr_channel;
|
|
|
|
|
|
|
|
|
|
if (account->is_connected)
|
|
|
|
|
if (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)
|
|
|
|
|
//user::free_all(this); // TOFIX
|
|
|
|
|
weechat_nicklist_remove_all(buffer);
|
|
|
|
|
for (auto& ptr_channel : channels)
|
|
|
|
|
{
|
|
|
|
|
weechat_nicklist_remove_all(ptr_channel->buffer);
|
|
|
|
|
weechat_nicklist_remove_all(ptr_channel.second.buffer);
|
|
|
|
|
weechat_printf(
|
|
|
|
|
ptr_channel->buffer,
|
|
|
|
|
ptr_channel.second.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", "");
|
|
|
|
|
//weechat_buffer_set(buffer, "localvar_del_away", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
account__close_connection(account);
|
|
|
|
|
reset();
|
|
|
|
|
|
|
|
|
|
if (account->buffer)
|
|
|
|
|
if (buffer)
|
|
|
|
|
{
|
|
|
|
|
weechat_printf(
|
|
|
|
|
account->buffer,
|
|
|
|
|
buffer,
|
|
|
|
|
_("%s%s: disconnected from account"),
|
|
|
|
|
weechat_prefix ("network"), WEECHAT_XMPP_PLUGIN_NAME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reconnect)
|
|
|
|
|
{
|
|
|
|
|
if (account->current_retry++ == 0)
|
|
|
|
|
if (current_retry++ == 0)
|
|
|
|
|
{
|
|
|
|
|
account->reconnect_delay = 5;
|
|
|
|
|
account->reconnect_start = time(NULL) + account->reconnect_delay;
|
|
|
|
|
reconnect_delay = 5;
|
|
|
|
|
reconnect_start = time(NULL) + reconnect_delay;
|
|
|
|
|
}
|
|
|
|
|
account->current_retry %= 5;
|
|
|
|
|
current_retry %= 5;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
account->current_retry = 0;
|
|
|
|
|
account->reconnect_delay = 0;
|
|
|
|
|
account->reconnect_start = 0;
|
|
|
|
|
current_retry = 0;
|
|
|
|
|
reconnect_delay = 0;
|
|
|
|
|
reconnect_start = 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) +
|
|
|
|
|
lag = 0;
|
|
|
|
|
lag_displayed = -1;
|
|
|
|
|
lag_check_time.tv_sec = 0;
|
|
|
|
|
lag_check_time.tv_usec = 0;
|
|
|
|
|
lag_next_check = time(NULL) +
|
|
|
|
|
weechat_config_integer(xmpp_config_network_lag_check);
|
|
|
|
|
account->lag_last_refresh = 0;
|
|
|
|
|
lag_last_refresh = 0;
|
|
|
|
|
account__set_lag(account);
|
|
|
|
|
*/ // lag based on xmpp ping
|
|
|
|
|
|
|
|
|
|
account->disconnected = !reconnect;
|
|
|
|
|
disconnected = !reconnect;
|
|
|
|
|
|
|
|
|
|
/* send signal "account_disconnected" with account name */
|
|
|
|
|
(void) weechat_hook_signal_send("xmpp_account_disconnected",
|
|
|
|
|
WEECHAT_HOOK_SIGNAL_STRING, account->name);
|
|
|
|
|
WEECHAT_HOOK_SIGNAL_STRING, name.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__disconnect_all()
|
|
|
|
|
void weechat::account::disconnect_all()
|
|
|
|
|
{
|
|
|
|
|
for (auto ptr_account : accounts)
|
|
|
|
|
for (auto& account : accounts)
|
|
|
|
|
{
|
|
|
|
|
account__disconnect(ptr_account.second, 0);
|
|
|
|
|
account.second.disconnect(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct t_gui_buffer *account__create_buffer(struct t_account *account)
|
|
|
|
|
struct t_gui_buffer *weechat::account::create_buffer()
|
|
|
|
|
{
|
|
|
|
|
char buffer_name[256], charset_modifier[256];
|
|
|
|
|
|
|
|
|
|
snprintf(buffer_name, sizeof(buffer_name),
|
|
|
|
|
"account.%s", account->name);
|
|
|
|
|
account->buffer = weechat_buffer_new(buffer_name,
|
|
|
|
|
buffer = weechat_buffer_new(fmt::format("account.{}", name).data(),
|
|
|
|
|
&input__data_cb, NULL, NULL,
|
|
|
|
|
&buffer__close_cb, NULL, NULL);
|
|
|
|
|
if (!account->buffer)
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return NULL;
|
|
|
|
|
weechat_printf(account->buffer, "xmpp: %s", account->name);
|
|
|
|
|
|
|
|
|
|
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_account", 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",
|
|
|
|
|
weechat_printf(buffer, "xmpp: %s", name.data());
|
|
|
|
|
|
|
|
|
|
if (!weechat_buffer_get_integer(buffer, "short_name_is_set"))
|
|
|
|
|
weechat_buffer_set(buffer, "short_name", name.data());
|
|
|
|
|
weechat_buffer_set(buffer, "localvar_set_type", "server");
|
|
|
|
|
weechat_buffer_set(buffer, "localvar_set_account", name.data());
|
|
|
|
|
weechat_buffer_set(buffer, "localvar_set_charset_modifier",
|
|
|
|
|
fmt::format("account.{}", name).data());
|
|
|
|
|
weechat_buffer_set(buffer, "title", name.data());
|
|
|
|
|
|
|
|
|
|
weechat_buffer_set(buffer, "nicklist", "1");
|
|
|
|
|
weechat_buffer_set(buffer, "nicklist_display_groups", "0");
|
|
|
|
|
weechat_buffer_set_pointer(buffer, "nicklist_callback",
|
|
|
|
|
(void*)&buffer__nickcmp_cb);
|
|
|
|
|
weechat_buffer_set_pointer(account->buffer, "nicklist_callback_pointer",
|
|
|
|
|
account);
|
|
|
|
|
weechat_buffer_set_pointer(buffer, "nicklist_callback_pointer",
|
|
|
|
|
this);
|
|
|
|
|
|
|
|
|
|
return account->buffer;
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void account__close_connection(struct t_account *account)
|
|
|
|
|
void weechat::account::reset()
|
|
|
|
|
{
|
|
|
|
|
if (account->connection)
|
|
|
|
|
if (connection)
|
|
|
|
|
{
|
|
|
|
|
if (xmpp_conn_is_connected(account->connection))
|
|
|
|
|
xmpp_disconnect(account->connection);
|
|
|
|
|
if (xmpp_conn_is_connected(connection))
|
|
|
|
|
xmpp_disconnect(connection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
account->is_connected = 0;
|
|
|
|
|
is_connected = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int account__connect(struct t_account *account)
|
|
|
|
|
int weechat::account::connect()
|
|
|
|
|
{
|
|
|
|
|
if (!account->buffer)
|
|
|
|
|
if (!buffer)
|
|
|
|
|
{
|
|
|
|
|
if (!account__create_buffer(account))
|
|
|
|
|
if (!create_buffer())
|
|
|
|
|
return 0;
|
|
|
|
|
weechat_buffer_set(account->buffer, "display", "auto");
|
|
|
|
|
weechat_buffer_set(buffer, "display", "auto");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
account__close_connection(account);
|
|
|
|
|
reset();
|
|
|
|
|
|
|
|
|
|
account->is_connected =
|
|
|
|
|
connection__connect(account, &account->connection, account_jid(account),
|
|
|
|
|
account_password(account), account_tls(account));
|
|
|
|
|
is_connected = connection.connect(std::string(jid()), std::string(password()), tls());
|
|
|
|
|
|
|
|
|
|
(void) weechat_hook_signal_send("xmpp_account_connecting",
|
|
|
|
|
WEECHAT_HOOK_SIGNAL_STRING, account->name);
|
|
|
|
|
WEECHAT_HOOK_SIGNAL_STRING, name.data());
|
|
|
|
|
|
|
|
|
|
return account->is_connected;
|
|
|
|
|
return is_connected;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int account__timer_cb(const void *pointer, void *data, int remaining_calls)
|
|
|
|
|
int weechat::account::timer_cb(const void *pointer, void *data, int remaining_calls)
|
|
|
|
|
{
|
|
|
|
|
(void) pointer;
|
|
|
|
|
(void) data;
|
|
|
|
@ -723,17 +452,17 @@ int account__timer_cb(const void *pointer, void *data, int remaining_calls)
|
|
|
|
|
{
|
|
|
|
|
if (accounts.empty()) return WEECHAT_RC_ERROR;
|
|
|
|
|
|
|
|
|
|
for (auto ptr_account : accounts)
|
|
|
|
|
for (auto& ptr_account : accounts)
|
|
|
|
|
{
|
|
|
|
|
if (ptr_account.second->is_connected
|
|
|
|
|
&& (xmpp_conn_is_connecting(ptr_account.second->connection)
|
|
|
|
|
|| xmpp_conn_is_connected(ptr_account.second->connection)))
|
|
|
|
|
connection__process(ptr_account.second->context, ptr_account.second->connection, 10);
|
|
|
|
|
else if (ptr_account.second->disconnected);
|
|
|
|
|
else if (ptr_account.second->reconnect_start > 0
|
|
|
|
|
&& ptr_account.second->reconnect_start < time(NULL))
|
|
|
|
|
if (ptr_account.second.is_connected
|
|
|
|
|
&& (xmpp_conn_is_connecting(ptr_account.second.connection)
|
|
|
|
|
|| xmpp_conn_is_connected(ptr_account.second.connection)))
|
|
|
|
|
ptr_account.second.connection.process(ptr_account.second.context, 10);
|
|
|
|
|
else if (ptr_account.second.disconnected);
|
|
|
|
|
else if (ptr_account.second.reconnect_start > 0
|
|
|
|
|
&& ptr_account.second.reconnect_start < time(NULL))
|
|
|
|
|
{
|
|
|
|
|
account__connect(ptr_account.second);
|
|
|
|
|
ptr_account.second.connect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|