mirror of https://github.com/bqv/weechat-xmpp
stubby
parent
8ed0913fd3
commit
e887e25edd
@ -0,0 +1,445 @@
|
|||||||
|
// 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 <stdint.h>
|
||||||
|
// #include <string.h>
|
||||||
|
// #include <stdio.h>
|
||||||
|
// #include <assert.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "account.hh"
|
||||||
|
#include "weechat.hh"
|
||||||
|
#include "strophe.hh"
|
||||||
|
#include "strophe.ipp"
|
||||||
|
#include "config.hh"
|
||||||
|
|
||||||
|
// #include "plugin.h"
|
||||||
|
// #include "input.h"
|
||||||
|
// #include "omemo.h"
|
||||||
|
// #include "connection.h"
|
||||||
|
// #include "user.h"
|
||||||
|
// #include "channel.h"
|
||||||
|
// #include "buffer.h"
|
||||||
|
#include "stubs.cpp"
|
||||||
|
|
||||||
|
std::map<std::string, weechat::xmpp::account> weechat::xmpp::globals::accounts;
|
||||||
|
|
||||||
|
std::map<std::string, weechat::config_option> weechat::xmpp::account::m_default_options;
|
||||||
|
std::map<std::string, weechat::xmpp::config::option_data> weechat::xmpp::account::m_option_defaults {
|
||||||
|
{ "jid", {"string", "XMPP Account JID", "", ""} },
|
||||||
|
{ "password", {"string", "XMPP Account Password", "", ""} },
|
||||||
|
{ "tls", {"integer", "XMPP Server TLS Policy", "normal", "disable|normal|trust"} },
|
||||||
|
{ "nickname", {"string", "XMPP Account Nickname", "", ""} },
|
||||||
|
{ "autoconnect", {"boolean", "Autoconnect XMPP Account", "", ""} },
|
||||||
|
{ "resource", {"string", "XMPP Account Resource", "", ""} },
|
||||||
|
{ "status", {"string", "XMPP Account Login Status", "probably about to segfault", ""} },
|
||||||
|
{ "pgp_pubring_path", {"string", "XMPP Account PGP Public Keyring Path",
|
||||||
|
"${weechat_data_dir}/pubring.gpg", ""} },
|
||||||
|
{ "pgp_secring_path", {"string", "XMPP Account PGP Secure Keyring Path",
|
||||||
|
"${weechat_data_dir}/secring.gpg", ""} },
|
||||||
|
{ "pgp_keyid", {"string", "XMPP Account PGP Key ID", "", ""} },
|
||||||
|
};
|
||||||
|
|
||||||
|
template xmpp::context::context(weechat::xmpp::account&);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void xmpp::logger<weechat::xmpp::account>::emit_weechat(
|
||||||
|
weechat::xmpp::account& account, const level level,
|
||||||
|
std::string_view area, std::string_view msg)
|
||||||
|
{
|
||||||
|
using logger = xmpp::logger<weechat::xmpp::account>;
|
||||||
|
|
||||||
|
const char *tags = level > logger::debug ? "no_log" : nullptr;
|
||||||
|
|
||||||
|
std::string_view xml;
|
||||||
|
if (std::size_t xmlpos = msg.find('<'); (level == logger::debug) &&
|
||||||
|
(xmlpos != msg.npos))
|
||||||
|
{
|
||||||
|
xml = msg.substr(xmlpos);
|
||||||
|
|
||||||
|
auto nullfd = std::unique_ptr<FILE, decltype(std::fclose)*>{
|
||||||
|
std::fopen("/dev/null", "w+"),
|
||||||
|
std::fclose
|
||||||
|
};
|
||||||
|
xml::set_error_context<FILE>(&*nullfd);
|
||||||
|
|
||||||
|
std::string_view header = msg.substr(0, xmlpos);
|
||||||
|
xml::document doc(xml);
|
||||||
|
if (!doc) {
|
||||||
|
weechat::printf(account.buffer,
|
||||||
|
"xml: Error parsing the xml document");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const char *colour = weechat::color("blue");
|
||||||
|
if (auto root = doc.root())
|
||||||
|
{
|
||||||
|
std::string tag = root->name();
|
||||||
|
if (tag == "message")
|
||||||
|
{
|
||||||
|
colour = weechat::color("green");
|
||||||
|
}
|
||||||
|
else if (tag == "presence")
|
||||||
|
{
|
||||||
|
colour = weechat::color("yellow");
|
||||||
|
}
|
||||||
|
else if (tag == "iq")
|
||||||
|
{
|
||||||
|
colour = weechat::color("red");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::string formatted = doc.format();
|
||||||
|
if (formatted.empty()) {
|
||||||
|
weechat::printf(account.buffer,
|
||||||
|
"xml: Error formatting the xml document");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int size = 0;
|
||||||
|
auto lines = std::unique_ptr<char*[],
|
||||||
|
decltype(weechat::string_free_split)*>{
|
||||||
|
weechat::string_split(formatted.data(), "\r\n", nullptr, 0, 0, &size),
|
||||||
|
weechat::string_free_split
|
||||||
|
};
|
||||||
|
if (lines[size-1][0] == 0)
|
||||||
|
lines[--size] = 0;
|
||||||
|
weechat::printf_date_tags(account.buffer, 0, tags,
|
||||||
|
weechat::gettext("%s%s (%s): %s"),
|
||||||
|
weechat::prefix("network"), area,
|
||||||
|
level.name(), header);
|
||||||
|
for (int i = 1; i < size; i++)
|
||||||
|
weechat::printf_date_tags(account.buffer, 0, tags,
|
||||||
|
weechat::gettext("%s%s"),
|
||||||
|
colour, lines[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
weechat::printf_date_tags(account.buffer, 0, tags,
|
||||||
|
weechat::gettext("%s%s (%s): %s"),
|
||||||
|
weechat::prefix("network"), area,
|
||||||
|
level.name(), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
weechat::xmpp::account::account(std::string name)
|
||||||
|
: context(*this)
|
||||||
|
, connection(this->context)
|
||||||
|
, buffer(name, {}, {})
|
||||||
|
{
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
this->ready = false;
|
||||||
|
this->active = false;
|
||||||
|
|
||||||
|
this->current_retry = 0;
|
||||||
|
this->reconnect_delay = 0;
|
||||||
|
this->reconnect_start = 0;
|
||||||
|
|
||||||
|
this->omemo = nullptr;
|
||||||
|
this->pgp = nullptr;
|
||||||
|
|
||||||
|
for (auto it = this->m_option_defaults.begin(); it != this->m_option_defaults.end(); it++)
|
||||||
|
{
|
||||||
|
std::string option_name = this->name + '.' + it->first
|
||||||
|
+ " << xmpp.account_default." + it->first;
|
||||||
|
|
||||||
|
auto [option, success] = this->m_options.try_emplace(it->first,
|
||||||
|
weechat::globals::plugin.config().file(),
|
||||||
|
weechat::globals::plugin.config().section_account(),
|
||||||
|
option_name, it->second.type,
|
||||||
|
weechat::gettext(it->second.description.data()),
|
||||||
|
it->second.range, 0, 0, it->second.value, it->second.value, false,
|
||||||
|
std::function([this](weechat::config_option&, std::string){ return true; }),
|
||||||
|
std::function([this](weechat::config_option&){ }),
|
||||||
|
std::function([this](weechat::config_option&){ }));
|
||||||
|
if (!success)
|
||||||
|
throw weechat::error("duplicate option key");
|
||||||
|
//option.change_cb(it->first, nullptr, this->m_options[it->first]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool weechat::xmpp::account::connected()
|
||||||
|
{
|
||||||
|
return xmpp::xmpp_conn_is_connected(this->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void weechat::xmpp::account::disconnect(bool reconnect)
|
||||||
|
{
|
||||||
|
if (this->connected())
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* remove all nicks and write disconnection message on each
|
||||||
|
* channel/private buffer
|
||||||
|
*/
|
||||||
|
c::user__free_all(*this);
|
||||||
|
weechat::nicklist_remove_all(this->buffer);
|
||||||
|
for (auto& [name, channel] : this->channels)
|
||||||
|
{
|
||||||
|
weechat::nicklist_remove_all(channel->buffer);
|
||||||
|
weechat::printf(channel->buffer,
|
||||||
|
weechat::gettext("%s%s: disconnected from account"),
|
||||||
|
weechat::prefix("network"), weechat::globals::plugin.name());
|
||||||
|
}
|
||||||
|
/* remove away status on account buffer */
|
||||||
|
//weechat::buffer_set(this->buffer, "localvar_del_away", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->close_connection();
|
||||||
|
|
||||||
|
if (this->buffer)
|
||||||
|
{
|
||||||
|
weechat::printf(this->buffer,
|
||||||
|
weechat::gettext("%s%s: disconnected from account"),
|
||||||
|
weechat::prefix("network"), weechat::globals::plugin.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reconnect)
|
||||||
|
{
|
||||||
|
if (this->current_retry++ == 0)
|
||||||
|
{
|
||||||
|
this->reconnect_delay = 5;
|
||||||
|
this->reconnect_start = time(nullptr) + this->reconnect_delay;
|
||||||
|
}
|
||||||
|
this->current_retry %= 5;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->current_retry = 0;
|
||||||
|
this->reconnect_delay = 0;
|
||||||
|
this->reconnect_start = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->active = reconnect;
|
||||||
|
|
||||||
|
/* send signal "account_disconnected" with account name */
|
||||||
|
weechat::hook_signal_send<char*>("xmpp_account_disconnected",
|
||||||
|
WEECHAT_HOOK_SIGNAL_STRING, this->name.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
weechat::gui_buffer weechat::xmpp::account::create_buffer()
|
||||||
|
{
|
||||||
|
std::string name = "account." + this->name;
|
||||||
|
this->buffer = weechat::gui_buffer(name.data(),
|
||||||
|
weechat::gui_buffer::input_callback(),
|
||||||
|
weechat::gui_buffer::close_callback());
|
||||||
|
if (!this->buffer)
|
||||||
|
throw weechat::error("failed to create account buffer");
|
||||||
|
|
||||||
|
if (!weechat::buffer_get_integer(this->buffer, "short_name_is_set"))
|
||||||
|
weechat::buffer_set(this->buffer, "short_name", this->name.data());
|
||||||
|
weechat::buffer_set(this->buffer, "localvar_set_type", "server");
|
||||||
|
weechat::buffer_set(this->buffer, "localvar_set_server", this->name.data());
|
||||||
|
weechat::buffer_set(this->buffer, "localvar_set_channel", this->name.data());
|
||||||
|
std::string charset_modifier = "account." + this->name;
|
||||||
|
weechat::buffer_set(this->buffer, "localvar_set_charset_modifier",
|
||||||
|
charset_modifier.data());
|
||||||
|
weechat::buffer_set(this->buffer, "title", this->name.data());
|
||||||
|
|
||||||
|
weechat::buffer_set(this->buffer, "nicklist", "1");
|
||||||
|
weechat::buffer_set(this->buffer, "nicklist_display_groups", "0");
|
||||||
|
weechat::buffer_set_pointer(this->buffer, "nicklist_callback",
|
||||||
|
reinterpret_cast<void*>(static_cast<void (*)(
|
||||||
|
const void*, void*, weechat::t_gui_buffer*,
|
||||||
|
const char*, const char*)>(
|
||||||
|
[](const void *pointer, void*,
|
||||||
|
struct t_gui_buffer *buffer,
|
||||||
|
const char *nick1, const char *nick2) {
|
||||||
|
auto& account = *reinterpret_cast<
|
||||||
|
const weechat::xmpp::account*>(pointer);
|
||||||
|
(void) account;
|
||||||
|
c::buffer__nickcmp_cb((c::t_gui_buffer*)buffer,
|
||||||
|
nick1, nick2);
|
||||||
|
})));
|
||||||
|
weechat::buffer_set_pointer(this->buffer, "nicklist_callback_pointer",
|
||||||
|
this);
|
||||||
|
|
||||||
|
return this->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void weechat::xmpp::account::close_connection()
|
||||||
|
{
|
||||||
|
if (this->connection)
|
||||||
|
{
|
||||||
|
if (xmpp::xmpp_conn_is_connected(this->connection))
|
||||||
|
xmpp::xmpp_disconnect(this->connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool weechat::xmpp::account::connect()
|
||||||
|
{
|
||||||
|
if (!this->buffer)
|
||||||
|
{
|
||||||
|
if (!this->create_buffer())
|
||||||
|
return false;
|
||||||
|
weechat::buffer_set(this->buffer, "display", "auto");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->close_connection();
|
||||||
|
|
||||||
|
c::connection__connect(*this, this->connection, this->jid(),
|
||||||
|
this->password(), this->tls());
|
||||||
|
|
||||||
|
weechat::hook_signal_send("xmpp_account_connecting",
|
||||||
|
WEECHAT_HOOK_SIGNAL_STRING, this->name.data());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool weechat::xmpp::account::timer_cb(int)
|
||||||
|
{
|
||||||
|
for (auto& [name, account] : weechat::xmpp::globals::accounts)
|
||||||
|
{
|
||||||
|
if (xmpp_conn_is_connecting(account.connection)
|
||||||
|
|| xmpp_conn_is_connected(account.connection))
|
||||||
|
c::connection__process(account.context, account.connection, 10);
|
||||||
|
else if (account.active && account.reconnect_start > 0
|
||||||
|
&& account.reconnect_start < time(nullptr))
|
||||||
|
{
|
||||||
|
account.connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void weechat::xmpp::account::disconnect_all()
|
||||||
|
{
|
||||||
|
for (auto it = weechat::xmpp::globals::accounts.begin();
|
||||||
|
it != weechat::xmpp::globals::accounts.end(); it++)
|
||||||
|
{
|
||||||
|
it->second.disconnect(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::map<std::string, weechat::xmpp::account>::iterator, bool>
|
||||||
|
weechat::xmpp::account::create(std::string name)
|
||||||
|
{
|
||||||
|
return weechat::xmpp::globals::accounts.try_emplace(name, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void weechat::xmpp::account::init_defaults(config_file& config_file, config_section& section)
|
||||||
|
{
|
||||||
|
for (auto& [name, option_data] : weechat::xmpp::account::m_option_defaults)
|
||||||
|
{
|
||||||
|
weechat::xmpp::account::m_default_options.try_emplace(name,
|
||||||
|
weechat::config_option(
|
||||||
|
config_file, section, name,
|
||||||
|
option_data.type, option_data.description, option_data.range,
|
||||||
|
0, 0, option_data.value, option_data.value, true, {}, {}, {})).first->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool weechat::xmpp::account::reload(config_file&)
|
||||||
|
{
|
||||||
|
for (auto& [_, account] : weechat::xmpp::globals::accounts)
|
||||||
|
account.ready = false;
|
||||||
|
|
||||||
|
if (!weechat::config_reload(weechat::globals::plugin.config().file()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto& [_, account] : weechat::xmpp::globals::accounts)
|
||||||
|
{
|
||||||
|
account.ready = true;
|
||||||
|
|
||||||
|
std::string ac_global = weechat::info_get("auto_connect", nullptr);
|
||||||
|
bool ac_local = account.autoconnect();
|
||||||
|
if (ac_local && ac_global == "1")
|
||||||
|
account.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int weechat::xmpp::account::read_cb(config_file& config_file, config_section& section,
|
||||||
|
std::string option_name, std::string value)
|
||||||
|
{
|
||||||
|
int rc = WEECHAT_CONFIG_OPTION_SET_ERROR;
|
||||||
|
|
||||||
|
if (!option_name.empty())
|
||||||
|
{
|
||||||
|
if (std::size_t pos_option = option_name.find('.');
|
||||||
|
pos_option != option_name.npos)
|
||||||
|
{
|
||||||
|
std::string account_name = option_name.substr(0, pos_option);
|
||||||
|
std::string option_id = option_name.substr(++pos_option);
|
||||||
|
auto data_it = weechat::xmpp::account::m_option_defaults.find(option_id);
|
||||||
|
if (data_it == weechat::xmpp::account::m_option_defaults.end())
|
||||||
|
{
|
||||||
|
rc = WEECHAT_CONFIG_OPTION_SET_OPTION_NOT_FOUND;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
auto& option_data = data_it->second;
|
||||||
|
|
||||||
|
if (account_name == "account_default")
|
||||||
|
|
||||||
|
{
|
||||||
|
auto& option =
|
||||||
|
weechat::xmpp::account::m_default_options.try_emplace(option_id,
|
||||||
|
weechat::config_option(
|
||||||
|
config_file, section, option_id,
|
||||||
|
option_data.type, option_data.description, option_data.range,
|
||||||
|
0, 0, option_data.value, option_data.value, true, {}, {}, {})).first->second;
|
||||||
|
|
||||||
|
rc = weechat::config_option_set(option, value.data(), true);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& item = weechat::xmpp::account::create(account_name).first;
|
||||||
|
weechat::xmpp::account& account = item->second;
|
||||||
|
|
||||||
|
auto& option = account.m_options.try_emplace(option_id,
|
||||||
|
weechat::config_option(
|
||||||
|
config_file, section, option_id,
|
||||||
|
option_data.type, option_data.description, option_data.range,
|
||||||
|
0, 0, option_data.value, option_data.value, true, {}, {}, {})).first->second;
|
||||||
|
|
||||||
|
rc = weechat::config_option_set(option, value.data(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == WEECHAT_CONFIG_OPTION_SET_ERROR)
|
||||||
|
{
|
||||||
|
weechat::printf(nullptr,
|
||||||
|
weechat::gettext("%s%s: error creating account option \"%s\""),
|
||||||
|
weechat::prefix("error"), weechat::globals::plugin.name().data(),
|
||||||
|
option_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int weechat::xmpp::account::write_cb(config_file& config_file, std::string section_name)
|
||||||
|
{
|
||||||
|
if (!weechat::config_write_line(config_file, section_name.data(), nullptr))
|
||||||
|
return WEECHAT_CONFIG_WRITE_ERROR;
|
||||||
|
|
||||||
|
for (auto& [_, account] : weechat::xmpp::globals::accounts)
|
||||||
|
{
|
||||||
|
for (auto& [name, option] : account.m_options)
|
||||||
|
{
|
||||||
|
if (!weechat::config_write_option(config_file, option))
|
||||||
|
return WEECHAT_CONFIG_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return WEECHAT_CONFIG_WRITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void weechat::xmpp::account::change_cb(config_option& option)
|
||||||
|
{
|
||||||
|
std::string name = option.string("name");
|
||||||
|
std::string value = option.string("value");
|
||||||
|
|
||||||
|
int split_num;
|
||||||
|
char **split = weechat::string_split(name.data(), ".", nullptr, 0, 2, &split_num);
|
||||||
|
auto it = weechat::xmpp::globals::accounts.find(split[0]);
|
||||||
|
if (split_num >= 2 && it != weechat::xmpp::globals::accounts.end())
|
||||||
|
{
|
||||||
|
std::string key = split[1];
|
||||||
|
|
||||||
|
(void) key;
|
||||||
|
(void) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
weechat::string_free_split(split);
|
||||||
|
}
|
@ -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/.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <map>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "plugin.hh"
|
||||||
|
#include "strophe.hh"
|
||||||
|
#include "config.hh"
|
||||||
|
|
||||||
|
namespace weechat::xmpp {
|
||||||
|
namespace xmpp = ::xmpp;
|
||||||
|
|
||||||
|
class account {
|
||||||
|
public:
|
||||||
|
explicit account(std::string name);
|
||||||
|
|
||||||
|
struct option_data {
|
||||||
|
std::string type;
|
||||||
|
std::string description;
|
||||||
|
std::string value;
|
||||||
|
std::string range;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct device
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mam_query
|
||||||
|
{
|
||||||
|
std::string id;
|
||||||
|
std::string with;
|
||||||
|
std::optional<std::time_t> start;
|
||||||
|
std::optional<std::time_t> end;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
bool ready;
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
int current_retry;
|
||||||
|
int reconnect_delay;
|
||||||
|
std::time_t reconnect_start;
|
||||||
|
|
||||||
|
xmpp::context context;
|
||||||
|
xmpp::connection connection;
|
||||||
|
|
||||||
|
weechat::gui_buffer buffer;
|
||||||
|
|
||||||
|
struct t_omemo *omemo;
|
||||||
|
struct t_pgp *pgp;
|
||||||
|
|
||||||
|
std::map<int, device> devices;
|
||||||
|
std::map<std::string, mam_query> mam_queries;
|
||||||
|
std::map<std::string, struct t_user*> users;
|
||||||
|
std::map<std::string, struct t_channel*> channels;
|
||||||
|
|
||||||
|
inline std::string jid() {
|
||||||
|
return this->connection && xmpp_conn_is_connected(this->connection)
|
||||||
|
? xmpp_jid_bare(this->context,
|
||||||
|
xmpp_conn_get_bound_jid(this->connection))
|
||||||
|
: weechat::config_string(this->m_options.at("jid"));
|
||||||
|
}
|
||||||
|
inline std::string jid_device() {
|
||||||
|
return this->connection && xmpp_conn_is_connected(this->connection)
|
||||||
|
? xmpp_conn_get_bound_jid(this->connection)
|
||||||
|
: xmpp_jid_new(this->context,
|
||||||
|
xmpp_jid_node(
|
||||||
|
this->context,
|
||||||
|
weechat::config_string(
|
||||||
|
this->m_options.at("jid"))),
|
||||||
|
xmpp_jid_domain(
|
||||||
|
this->context,
|
||||||
|
weechat::config_string(
|
||||||
|
this->m_options.at("jid"))),
|
||||||
|
"weechat");
|
||||||
|
}
|
||||||
|
inline weechat::config_option password() {
|
||||||
|
return weechat::config_option(this->m_options.at("password"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option tls() {
|
||||||
|
return weechat::config_option(this->m_options.at("tls"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option nickname() {
|
||||||
|
return weechat::config_option(this->m_options.at("nickname"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option autoconnect() {
|
||||||
|
return weechat::config_option(this->m_options.at("autoconnect"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option resource() {
|
||||||
|
return weechat::config_option(this->m_options.at("resource"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option status() {
|
||||||
|
return weechat::config_option(this->m_options.at("status"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option pgp_pubring_path() {
|
||||||
|
return weechat::config_option(this->m_options.at("pgp_pubring_path"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option pgp_secring_path() {
|
||||||
|
return weechat::config_option(this->m_options.at("pgp_secring_path"));
|
||||||
|
}
|
||||||
|
inline weechat::config_option pgp_keyid() {
|
||||||
|
return weechat::config_option(this->m_options.at("pgp_keyid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connected();
|
||||||
|
void disconnect(bool reconnect);
|
||||||
|
weechat::gui_buffer create_buffer();
|
||||||
|
void close_connection();
|
||||||
|
bool connect();
|
||||||
|
bool timer_cb(int remaining_calls);
|
||||||
|
|
||||||
|
static void disconnect_all();
|
||||||
|
|
||||||
|
static std::pair<std::map<std::string, account>::iterator, bool> create(std::string name);
|
||||||
|
|
||||||
|
static void init_defaults(config_file& config_file, config_section& section);
|
||||||
|
static bool reload(config_file& config_file);
|
||||||
|
static int read_cb(config_file& config_file, config_section& section,
|
||||||
|
std::string option_name, std::string value);
|
||||||
|
static int write_cb(config_file& config_file, std::string section_name);
|
||||||
|
static void change_cb(config_option& option);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, weechat::config_option> m_options;
|
||||||
|
|
||||||
|
static std::map<std::string, weechat::config_option> m_default_options;
|
||||||
|
static std::map<std::string, config::option_data> m_option_defaults;
|
||||||
|
|
||||||
|
friend class weechat::xmpp::config;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace globals {
|
||||||
|
extern std::map<std::string, account> accounts;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
// 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 "config.hh"
|
||||||
|
#include "plugin.hh"
|
||||||
|
#include "account.hh"
|
||||||
|
|
||||||
|
weechat::xmpp::config::config(std::string name)
|
||||||
|
: m_name(name)
|
||||||
|
, m_file(weechat::config_file(name, std::function(
|
||||||
|
[](weechat::config_file& file) {
|
||||||
|
return weechat::xmpp::account::reload(file);
|
||||||
|
})))
|
||||||
|
, m_section_look(weechat::config_section(
|
||||||
|
this->m_file, "look", false, false, {}, {}, {}, {}, {}))
|
||||||
|
, m_section_account_default(weechat::config_section(
|
||||||
|
this->m_file, "account_default", false, false, {}, {}, {}, {}, {}))
|
||||||
|
, m_section_account(weechat::config_section(
|
||||||
|
this->m_file, "account", false, false,
|
||||||
|
&weechat::xmpp::account::read_cb,
|
||||||
|
&weechat::xmpp::account::write_cb,
|
||||||
|
{}, {}, {}))
|
||||||
|
, m_look_nick_completion_smart(weechat::config_option(
|
||||||
|
this->m_file, this->m_section_look,
|
||||||
|
"nick_completion_smart", "integer",
|
||||||
|
weechat::gettext("smart completion for nicks (completes first with last speakers): "
|
||||||
|
"speakers = all speakers (including highlights), "
|
||||||
|
"speakers_highlights = only speakers with highlight"),
|
||||||
|
"off|speakers|speakers_highlights", 0, 0, "speakers", "", false,
|
||||||
|
{}, {}, {})) {
|
||||||
|
weechat::xmpp::account::init_defaults(this->m_file, this->m_section_account_default);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool weechat::xmpp::config::read()
|
||||||
|
{
|
||||||
|
return weechat::config_read(this->m_file) == weechat::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool weechat::xmpp::config::write()
|
||||||
|
{
|
||||||
|
return weechat::config_write(this->m_file) == weechat::ok;
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
// 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/.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <map>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "weechat.hh"
|
||||||
|
#include "strophe.hh"
|
||||||
|
|
||||||
|
namespace weechat::xmpp {
|
||||||
|
namespace xmpp = ::xmpp;
|
||||||
|
|
||||||
|
class config {
|
||||||
|
public:
|
||||||
|
inline config() : config(config::default_name) {}
|
||||||
|
explicit config(std::string name);
|
||||||
|
|
||||||
|
enum class nick_completion
|
||||||
|
{
|
||||||
|
SMART_OFF = 0,
|
||||||
|
SMART_SPEAKERS,
|
||||||
|
SMART_SPEAKERS_HIGHLIGHTS,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct option_data {
|
||||||
|
std::string type;
|
||||||
|
std::string description;
|
||||||
|
std::string value;
|
||||||
|
std::string range;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool read();
|
||||||
|
bool write();
|
||||||
|
|
||||||
|
inline std::string& name() { return this->m_name; }
|
||||||
|
|
||||||
|
inline weechat::config_file& file() { return this->m_file; }
|
||||||
|
inline weechat::config_section& section_account() { return this->m_section_account; }
|
||||||
|
inline weechat::config_section& section_account_default() { return this->m_section_account_default; }
|
||||||
|
|
||||||
|
inline nick_completion look_nick_completion_smart() {
|
||||||
|
int value = this->m_look_nick_completion_smart;
|
||||||
|
return static_cast<nick_completion>(value);;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const std::string default_name = "xmpp";
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
|
||||||
|
weechat::config_file m_file;
|
||||||
|
|
||||||
|
weechat::config_section m_section_look;
|
||||||
|
weechat::config_section m_section_account_default;
|
||||||
|
weechat::config_section m_section_account;
|
||||||
|
|
||||||
|
weechat::config_option m_look_nick_completion_smart;
|
||||||
|
|
||||||
|
std::map<std::string, weechat::config_option> m_account_default;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
(define-module (weechat)
|
||||||
|
#:use-module ((guix licenses) #:prefix license:)
|
||||||
|
#:use-module (guix download)
|
||||||
|
#:use-module (guix git-download)
|
||||||
|
#:use-module (guix utils)
|
||||||
|
#:use-module (guix packages)
|
||||||
|
#:use-module (guix utils)
|
||||||
|
#:use-module (guix build-system cmake)
|
||||||
|
#:use-module (guix build-system gnu)
|
||||||
|
#:use-module (guix build-system meson)
|
||||||
|
#:use-module (guix build-system python)
|
||||||
|
#:use-module (guix build-system qt)
|
||||||
|
#:use-module (gnu packages)
|
||||||
|
#:use-module (gnu packages admin)
|
||||||
|
#:use-module (gnu packages aspell)
|
||||||
|
#:use-module (gnu packages autogen)
|
||||||
|
#:use-module (gnu packages autotools)
|
||||||
|
#:use-module (gnu packages base)
|
||||||
|
#:use-module (gnu packages backup)
|
||||||
|
#:use-module (gnu packages check)
|
||||||
|
#:use-module (gnu packages compression)
|
||||||
|
#:use-module (gnu packages curl)
|
||||||
|
#:use-module (gnu packages cyrus-sasl)
|
||||||
|
#:use-module (gnu packages databases)
|
||||||
|
#:use-module (gnu packages file)
|
||||||
|
#:use-module (gnu packages gettext)
|
||||||
|
#:use-module (gnu packages geo)
|
||||||
|
#:use-module (gnu packages glib)
|
||||||
|
#:use-module (gnu packages gnome)
|
||||||
|
#:use-module (gnu packages gnupg)
|
||||||
|
#:use-module (gnu packages gtk)
|
||||||
|
#:use-module (gnu packages guile)
|
||||||
|
#:use-module (gnu packages irc)
|
||||||
|
#:use-module (gnu packages lua)
|
||||||
|
#:use-module (gnu packages lxqt)
|
||||||
|
#:use-module (gnu packages ncurses)
|
||||||
|
#:use-module (gnu packages openldap)
|
||||||
|
#:use-module (gnu packages kde)
|
||||||
|
#:use-module (gnu packages kde-frameworks)
|
||||||
|
#:use-module (gnu packages password-utils)
|
||||||
|
#:use-module (gnu packages pcre)
|
||||||
|
#:use-module (gnu packages perl)
|
||||||
|
#:use-module (gnu packages pkg-config)
|
||||||
|
#:use-module (gnu packages python)
|
||||||
|
#:use-module (gnu packages python-crypto)
|
||||||
|
#:use-module (gnu packages python-xyz)
|
||||||
|
#:use-module (gnu packages regex)
|
||||||
|
#:use-module (gnu packages ruby)
|
||||||
|
#:use-module (gnu packages sphinx)
|
||||||
|
#:use-module (gnu packages sqlite)
|
||||||
|
#:use-module (gnu packages qt)
|
||||||
|
#:use-module (gnu packages tcl)
|
||||||
|
#:use-module (gnu packages textutils)
|
||||||
|
#:use-module (gnu packages time)
|
||||||
|
#:use-module (gnu packages tls)
|
||||||
|
#:use-module (gnu packages web)
|
||||||
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-26))
|
||||||
|
|
||||||
|
(define-public weechat-dbg
|
||||||
|
(package
|
||||||
|
(inherit weechat)
|
||||||
|
(outputs '("out" "debug"))
|
||||||
|
(arguments
|
||||||
|
(substitute-keyword-arguments (package-arguments weechat)
|
||||||
|
((#:configure-flags configure-flags)
|
||||||
|
`(cons*
|
||||||
|
"-DCMAKE_BUILD_TYPE=DEBUG"
|
||||||
|
"-DCMAKE_C_FLAGS_DEBUG=\"-O0\""
|
||||||
|
"-DCMAKE_CXX_FLAGS_DEBUG=\"-O0\""
|
||||||
|
,configure-flags))
|
||||||
|
((#:phases phases)
|
||||||
|
`(modify-phases ,phases
|
||||||
|
(add-before 'configure 'setenv
|
||||||
|
(lambda* (#:key outputs #:allow-other-keys)
|
||||||
|
(let* ((out (assoc-ref outputs "out"))
|
||||||
|
(gcc (assoc-ref inputs "gcc-toolchain"))
|
||||||
|
(cppflags (string-append " -gdwarf-4 " (or (getenv "CXXFLAGS") "")))
|
||||||
|
(cflags (string-append " -gdwarf-4 " (or (getenv "CFLAGS") ""))))
|
||||||
|
(setenv "CXX" (string-append gcc "/bin/gcc " cppflags))
|
||||||
|
(setenv "CC" (string-append gcc "/bin/gcc " cflags))
|
||||||
|
#t)))))))))
|
||||||
|
|
||||||
|
weechat-dbg
|
@ -0,0 +1,39 @@
|
|||||||
|
// 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.hh"
|
||||||
|
|
||||||
|
namespace xmpp {
|
||||||
|
extern "C" {
|
||||||
|
#include <strophe.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename UserData>
|
||||||
|
context::context(UserData& data)
|
||||||
|
: context(xmpp_ctx_new(nullptr, const_cast<xmpp_log_t*>(static_cast<const xmpp_log_t*>(std::any_cast<logger<UserData>>(&this->m_logger))))) {
|
||||||
|
this->m_logger = logger(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename UserData>
|
||||||
|
logger<UserData>::logger(UserData& data)
|
||||||
|
: m_data(data) {
|
||||||
|
this->handler = [] (void *const userdata, const xmpp_log_level_t level,
|
||||||
|
const char *const area, const char *const msg) {
|
||||||
|
UserData& data = static_cast<logger<UserData>*>(userdata)->m_data;
|
||||||
|
logger::emit_weechat(data, level, area, msg);
|
||||||
|
};
|
||||||
|
this->userdata = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace xml {
|
||||||
|
extern "C" {
|
||||||
|
#include <libxml/xmlwriter.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void set_error_context(T *context) {
|
||||||
|
xmlGenericErrorContext = context;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
// 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/.
|
||||||
|
|
||||||
|
namespace c {
|
||||||
|
extern "C" {
|
||||||
|
#include "plugin.h"
|
||||||
|
// #include "connection.h"
|
||||||
|
void connection__init() { return; }
|
||||||
|
bool connection__connect(weechat::xmpp::account&, xmpp::connection&,
|
||||||
|
std::string, std::string, std::string) { return true; }
|
||||||
|
void connection__process(xmpp::context&, xmpp::connection&, int) { return; }
|
||||||
|
// #include "command.h"
|
||||||
|
void command__init() { return; }
|
||||||
|
// #include "input.h"
|
||||||
|
int input__text_changed_cb(const void*, void*, const char*, const char*, void*) { return 0; }
|
||||||
|
// #include "buffer.h"
|
||||||
|
std::string buffer__typing_bar_cb(weechat::gui_bar_item&, weechat::gui_window&,
|
||||||
|
weechat::gui_buffer&, weechat::hashtable&) { return ""; }
|
||||||
|
int buffer__close_cb(const void*, void*, struct t_gui_buffer*) { return 0; }
|
||||||
|
int buffer__nickcmp_cb(struct t_gui_buffer*, const char*, const char*) { return 0; }
|
||||||
|
// #include "completion.h"
|
||||||
|
void completion__init() { return; }
|
||||||
|
// #include "user.h"
|
||||||
|
void user__free_all(weechat::xmpp::account&) { return; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct weechat::xmpp::t_channel {
|
||||||
|
weechat::gui_buffer buffer;
|
||||||
|
};
|
@ -0,0 +1,10 @@
|
|||||||
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
#include "../account.hh"
|
||||||
|
|
||||||
|
TEST_CASE("create account")
|
||||||
|
{
|
||||||
|
weechat::xmpp::account acc("demo");
|
||||||
|
|
||||||
|
CHECK(acc.name == "demo");
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
#include "../config.hh"
|
||||||
|
|
||||||
|
TEST_CASE("create config")
|
||||||
|
{
|
||||||
|
weechat::xmpp::config cfg;
|
||||||
|
|
||||||
|
CHECK(cfg.name() == weechat::xmpp::config::default_name);
|
||||||
|
}
|
@ -1,11 +1,10 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
#include "../strophe.hh"
|
#include "../strophe.hh"
|
||||||
|
|
||||||
TEST_CASE("create context")
|
TEST_CASE("create context")
|
||||||
{
|
{
|
||||||
xmpp::context ctx;
|
xmpp::context ctx(0);
|
||||||
|
|
||||||
CHECK(ctx.get());
|
CHECK(ctx.get());
|
||||||
}
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
|
#include "../weechat.hh"
|
||||||
|
|
||||||
|
TEST_CASE("create error")
|
||||||
|
{
|
||||||
|
weechat::error err("content");
|
||||||
|
|
||||||
|
CHECK(err.what() == "content");
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
// 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 "weechat.hh"
|
||||||
|
#include "plugin.hh"
|
||||||
|
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
namespace weechat {
|
||||||
|
config_option::config_option(
|
||||||
|
config_file& config_file, config_section& section, std::string name,
|
||||||
|
std::string type, std::string description, std::string string_values,
|
||||||
|
int min, int max, std::string default_value, std::string value, bool null_value_allowed,
|
||||||
|
check_callback check_value_cb, change_callback change_cb, delete_callback delete_cb)
|
||||||
|
: config_option(weechat::config_new_option(
|
||||||
|
config_file, section, name.data(), type.data(),
|
||||||
|
description.data(), string_values.data(), min, max,
|
||||||
|
default_value.data(), value.data(), null_value_allowed,
|
||||||
|
this->m_check_cb, this->m_change_cb, this->m_delete_cb)) {
|
||||||
|
this->m_check_cb = check_value_cb;
|
||||||
|
this->m_change_cb = change_cb;
|
||||||
|
this->m_delete_cb = delete_cb;
|
||||||
|
this->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_option::config_option(struct t_config_option* option)
|
||||||
|
: std::reference_wrapper<struct t_config_option>(*option) {
|
||||||
|
if (!option)
|
||||||
|
throw weechat::error("failed to create config option");
|
||||||
|
}
|
||||||
|
|
||||||
|
config_option::operator int () const {
|
||||||
|
return weechat::config_integer(*this);
|
||||||
|
}
|
||||||
|
config_option::operator bool () const {
|
||||||
|
return weechat::config_boolean(*this);
|
||||||
|
}
|
||||||
|
config_option::operator std::string () const {
|
||||||
|
return weechat::config_string(*this);
|
||||||
|
}
|
||||||
|
std::string config_option::string(std::string property) const {
|
||||||
|
return weechat::config_option_get_string(*this, property.data());
|
||||||
|
}
|
||||||
|
config_option& config_option::operator= (std::string_view value) {
|
||||||
|
weechat::config_option_set(*this, std::string(value).data(), 1);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_section::config_section(config_file& config_file, std::string name,
|
||||||
|
bool user_can_add_options, bool user_can_delete_options,
|
||||||
|
read_callback read_cb, write_callback write_cb,
|
||||||
|
write_default_callback write_default_cb,
|
||||||
|
create_option_callback create_option_cb,
|
||||||
|
delete_option_callback delete_option_cb)
|
||||||
|
: config_section(weechat::config_new_section(config_file, name.data(),
|
||||||
|
user_can_add_options, user_can_delete_options,
|
||||||
|
this->m_read_cb, this->m_write_cb,
|
||||||
|
this->m_write_default_cb,
|
||||||
|
this->m_create_option_cb,
|
||||||
|
this->m_delete_option_cb)) {
|
||||||
|
this->m_read_cb = read_cb;
|
||||||
|
this->m_write_cb = write_cb;
|
||||||
|
this->m_write_default_cb = write_default_cb;
|
||||||
|
this->m_create_option_cb = create_option_cb;
|
||||||
|
this->m_delete_option_cb = delete_option_cb;
|
||||||
|
this->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_section::config_section(struct t_config_section* section)
|
||||||
|
: std::reference_wrapper<struct t_config_section>(*section) {
|
||||||
|
if (!section)
|
||||||
|
throw weechat::error("failed to create config section");
|
||||||
|
}
|
||||||
|
|
||||||
|
config_file::config_file(std::string name, reload_callback reload_cb)
|
||||||
|
: config_file(weechat::config_new(name.data(), this->m_reload_cb)) {
|
||||||
|
this->m_reload_cb = reload_cb;
|
||||||
|
this->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_file::config_file(struct t_config_file* file)
|
||||||
|
: std::reference_wrapper<struct t_config_file>(*file) {
|
||||||
|
if (!file)
|
||||||
|
throw weechat::error("failed to create config file");
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_bar_item::gui_bar_item(std::string_view name, gui_bar_item::build_callback callback)
|
||||||
|
: gui_bar_item(weechat::bar_item_new(name.data(), this->m_cb)) {
|
||||||
|
this->m_cb = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_buffer::gui_buffer(std::string name, gui_buffer::input_callback input_cb,
|
||||||
|
gui_buffer::close_callback close_cb)
|
||||||
|
: gui_buffer(weechat::buffer_new(name.data(), this->m_input_cb, this->m_close_cb)) {
|
||||||
|
this->m_input_cb = input_cb;
|
||||||
|
this->m_close_cb = close_cb;
|
||||||
|
this->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_buffer::gui_buffer(struct t_gui_buffer* buffer)
|
||||||
|
: std::reference_wrapper<struct t_gui_buffer>(*buffer) {
|
||||||
|
if (!buffer)
|
||||||
|
throw weechat::error("failed to create buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_buffer::~gui_buffer() {
|
||||||
|
weechat::buffer_close(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_bar_item::gui_bar_item(struct t_gui_bar_item* item)
|
||||||
|
: std::reference_wrapper<struct t_gui_bar_item>(*item) {
|
||||||
|
if (!item)
|
||||||
|
throw weechat::error("failed to create bar item");
|
||||||
|
}
|
||||||
|
|
||||||
|
gui_bar_item::~gui_bar_item() {
|
||||||
|
weechat::bar_item_remove(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
hook::hook(struct t_hook* hook)
|
||||||
|
: std::reference_wrapper<struct t_hook>(*hook) {
|
||||||
|
if (!hook)
|
||||||
|
throw weechat::error("failed to create hook timer");
|
||||||
|
}
|
||||||
|
|
||||||
|
hook::hook(long interval, int align_second, int max_calls,
|
||||||
|
hook::timer_callback callback)
|
||||||
|
: hook(weechat::hook_timer(interval, align_second, max_calls,
|
||||||
|
callback ? &this->m_timer_cb : nullptr)) {
|
||||||
|
this->m_timer_cb = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
hook::~hook() {
|
||||||
|
weechat::unhook(*this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,238 @@
|
|||||||
|
// 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/.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace weechat {
|
||||||
|
extern "C" {
|
||||||
|
#include <weechat/weechat-plugin.h>
|
||||||
|
|
||||||
|
class config_option; //typedef struct t_config_option config_option;
|
||||||
|
class config_section; //typedef struct t_config_section config_section;
|
||||||
|
class config_file; //typedef struct t_config_file config_file;
|
||||||
|
typedef struct t_gui_window gui_window;
|
||||||
|
class gui_buffer; //typedef struct t_gui_buffer gui_buffer;
|
||||||
|
typedef struct t_gui_bar gui_bar;
|
||||||
|
class gui_bar_item; //typedef struct t_gui_bar_item gui_bar_item;
|
||||||
|
typedef struct t_gui_bar_window gui_bar_window;
|
||||||
|
typedef struct t_gui_completion gui_completion;
|
||||||
|
typedef struct t_gui_nick gui_nick;
|
||||||
|
typedef struct t_gui_nick_group gui_nick_group;
|
||||||
|
typedef struct t_infolist infolist;
|
||||||
|
typedef struct t_infolist_item infolist_item;
|
||||||
|
typedef struct t_upgrade_file upgrade_file;
|
||||||
|
typedef struct t_weelist weelist;
|
||||||
|
typedef struct t_weelist_item weelist_item;
|
||||||
|
typedef struct t_arraylist arraylist;
|
||||||
|
typedef struct t_hashtable hashtable;
|
||||||
|
typedef struct t_hdata hdata;
|
||||||
|
class hook; //typedef struct t_hook hook;
|
||||||
|
class plugin; //typedef struct t_weechat_plugin weechat_plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum errc : int {
|
||||||
|
ok = WEECHAT_RC_OK,
|
||||||
|
eat = WEECHAT_RC_OK_EAT,
|
||||||
|
err = WEECHAT_RC_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
class error : virtual public std::runtime_error {
|
||||||
|
public:
|
||||||
|
explicit inline error(const std::string_view subject)
|
||||||
|
: std::runtime_error(std::string(subject)) {
|
||||||
|
}
|
||||||
|
virtual ~error() throw () {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class config_option : public std::reference_wrapper<struct t_config_option> {
|
||||||
|
public:
|
||||||
|
typedef int (*check_fn)(const void *, void *, struct t_config_option *, const char *);
|
||||||
|
typedef std::function<bool(config_option& option, std::string value)> check_callback;
|
||||||
|
typedef void (*change_fn)(const void *, void *, struct t_config_option *);
|
||||||
|
typedef std::function<void(config_option& option)> change_callback;
|
||||||
|
typedef void (*delete_fn)(const void *, void *, struct t_config_option *);
|
||||||
|
typedef std::function<void(config_option& option)> delete_callback;
|
||||||
|
|
||||||
|
config_option(
|
||||||
|
config_file& config_file, config_section& section, std::string name,
|
||||||
|
std::string type, std::string description, std::string string_values,
|
||||||
|
int min, int max, std::string default_value, std::string value, bool null_value_allowed,
|
||||||
|
check_callback check_value_cb, change_callback change_cb, delete_callback delete_cb);
|
||||||
|
explicit config_option(struct t_config_option* config_option);
|
||||||
|
inline ~config_option() {}
|
||||||
|
|
||||||
|
inline operator struct t_config_option* () const { return &this->get(); }
|
||||||
|
operator int () const;
|
||||||
|
operator bool () const;
|
||||||
|
operator std::string () const;
|
||||||
|
std::string string(std::string property) const;
|
||||||
|
template<typename T> T *pointer(std::string property) const;
|
||||||
|
config_option& operator= (std::string_view value);
|
||||||
|
inline config_option& operator= (struct t_config_option* config_option_ptr) {
|
||||||
|
*this = config_option_ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string name() const { return this->m_name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
check_callback m_check_cb;
|
||||||
|
change_callback m_change_cb;
|
||||||
|
delete_callback m_delete_cb;
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class config_section : public std::reference_wrapper<struct t_config_section> {
|
||||||
|
public:
|
||||||
|
typedef int (*read_fn)(const void *, void *, struct t_config_file *, struct t_config_section *,
|
||||||
|
const char *, const char *);
|
||||||
|
typedef std::function<int(config_file& config_file, config_section& section,
|
||||||
|
std::string option_name, std::string value)> read_callback;
|
||||||
|
typedef int (*write_fn)(const void *, void *, struct t_config_file *, const char *);
|
||||||
|
typedef std::function<int(config_file& config_file,
|
||||||
|
std::string section_name)> write_callback;
|
||||||
|
typedef int (*write_default_fn)(const void *, void *, struct t_config_file *, const char *);
|
||||||
|
typedef std::function<int(config_file& config_file,
|
||||||
|
std::string section_name)> write_default_callback;
|
||||||
|
typedef int (*create_option_fn)(const void *, void *, struct t_config_file *, struct t_config_section *,
|
||||||
|
const char *, const char *);
|
||||||
|
typedef std::function<int(config_file& config_file, config_section& section,
|
||||||
|
std::string option_name, std::string value)> create_option_callback;
|
||||||
|
typedef int (*delete_option_fn)(const void *, void *, struct t_config_file *, struct t_config_section *,
|
||||||
|
struct t_config_option *);
|
||||||
|
typedef std::function<int(config_file& config_file, config_section& section,
|
||||||
|
config_option& option)> delete_option_callback;
|
||||||
|
|
||||||
|
config_section(
|
||||||
|
config_file& config_file, std::string name,
|
||||||
|
bool user_can_add_options, bool user_can_delete_options,
|
||||||
|
read_callback read_cb, write_callback write_cb,
|
||||||
|
write_default_callback write_default_cb,
|
||||||
|
create_option_callback create_option_cb,
|
||||||
|
delete_option_callback delete_option_cb);
|
||||||
|
explicit config_section(struct t_config_section* config_section);
|
||||||
|
inline ~config_section() {}
|
||||||
|
|
||||||
|
inline operator struct t_config_section* () const { return &this->get(); }
|
||||||
|
inline config_section& operator= (struct t_config_section* config_section_ptr) {
|
||||||
|
*this = config_section_ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string name() const { return this->m_name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
|
||||||
|
read_callback m_read_cb;
|
||||||
|
write_callback m_write_cb;
|
||||||
|
write_default_callback m_write_default_cb;
|
||||||
|
create_option_callback m_create_option_cb;
|
||||||
|
delete_option_callback m_delete_option_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
class config_file : public std::reference_wrapper<struct t_config_file> {
|
||||||
|
public:
|
||||||
|
typedef int (*reload_fn)(const void *, void *, struct t_config_file *);
|
||||||
|
typedef std::function<int(config_file& config_file)> reload_callback;
|
||||||
|
|
||||||
|
config_file(std::string name, reload_callback reload_cb);
|
||||||
|
explicit config_file(struct t_config_file* config_file);
|
||||||
|
inline ~config_file() {}
|
||||||
|
|
||||||
|
inline operator struct t_config_file* () const { return &this->get(); }
|
||||||
|
inline config_file& operator= (struct t_config_file* config_file_ptr) {
|
||||||
|
*this = config_file_ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string name() const { return this->m_name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_name;
|
||||||
|
|
||||||
|
reload_callback m_reload_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
class gui_buffer : std::reference_wrapper<struct t_gui_buffer> {
|
||||||
|
public:
|
||||||
|
typedef int (*input_fn)(const void *, void *, struct t_gui_buffer *, const char *);
|
||||||
|
typedef std::function<errc(gui_buffer& buffer,
|
||||||
|
std::string input_data)> input_callback;
|
||||||
|
typedef int (*close_fn)(const void *, void *, struct t_gui_buffer *);
|
||||||
|
typedef std::function<errc(gui_buffer& buffer)> close_callback;
|
||||||
|
|
||||||
|
gui_buffer(std::string name, input_callback input_cb, close_callback close_cb);
|
||||||
|
explicit gui_buffer(struct t_gui_buffer* gui_buffer);
|
||||||
|
~gui_buffer();
|
||||||
|
|
||||||
|
inline operator struct t_gui_buffer* () const { return &this->get(); }
|
||||||
|
inline gui_buffer& operator= (struct t_gui_buffer* gui_buffer_ptr) {
|
||||||
|
*this = gui_buffer_ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
private:
|
||||||
|
input_callback m_input_cb;
|
||||||
|
close_callback m_close_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
class gui_bar_item : public std::reference_wrapper<struct t_gui_bar_item> {
|
||||||
|
public:
|
||||||
|
typedef char* (*build_fn)(const void *, void *, struct t_gui_bar_item *, struct t_gui_window *,
|
||||||
|
struct t_gui_buffer *, struct t_hashtable *);
|
||||||
|
typedef std::function<std::string(gui_bar_item&, gui_window*,
|
||||||
|
gui_buffer&, hashtable*)> build_callback;
|
||||||
|
|
||||||
|
gui_bar_item(std::string_view name, build_callback callback);
|
||||||
|
explicit gui_bar_item(struct t_gui_bar_item* item);
|
||||||
|
~gui_bar_item();
|
||||||
|
|
||||||
|
void update(std::string_view name);
|
||||||
|
|
||||||
|
inline operator struct t_gui_bar_item* () const { return &this->get(); }
|
||||||
|
inline gui_bar_item& operator= (struct t_gui_bar_item* item_ptr) {
|
||||||
|
*this = item_ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gui_bar_item search(std::string_view name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
build_callback m_cb;
|
||||||
|
};
|
||||||
|
|
||||||
|
class hook : public std::reference_wrapper<struct t_hook> {
|
||||||
|
public:
|
||||||
|
typedef int (*timer_fn)(const void *, void *, int remaining_calls);
|
||||||
|
typedef std::function<errc(int remaining_calls)> timer_callback;
|
||||||
|
|
||||||
|
hook(long interval, int align_second, int max_calls, timer_callback callback);
|
||||||
|
explicit hook(struct t_hook* hook);
|
||||||
|
~hook();
|
||||||
|
|
||||||
|
inline operator struct t_hook* () const { return &this->get(); }
|
||||||
|
inline hook& operator= (struct t_hook* hook_ptr) {
|
||||||
|
*this = hook_ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
timer_callback m_timer_cb;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -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/.
|
||||||
|
|
||||||
|
#include "weechat.hh"
|
||||||
|
#include "plugin.hh"
|
||||||
|
|
||||||
|
namespace weechat {
|
||||||
|
template<typename T>
|
||||||
|
T *config_option::pointer(std::string property) const {
|
||||||
|
return weechat::config_option_get_pointer<T*>(*this, property.data());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue