v2
Tony Olagbaiye 3 years ago
parent 8ed0913fd3
commit e887e25edd
No known key found for this signature in database
GPG Key ID: 9E2FF3BDEBDFC910

@ -0,0 +1,2 @@
CompileFlags:
Add: -ferror-limit=0

@ -11,5 +11,6 @@
" ")))
(flycheck-clang-warnings . ("all" "extra" "error-implicit-function-declaration" "no-missing-field-initializers"))
(flycheck-clang-language-standard . "c++17")
(flycheck-checker . c/c++-clang)
(flycheck-gcc-language-standard . "c++17")
(flycheck-checker . c/c++-gcc)
(projectile-project-compilation-cmd . "make && (make test || true)")))

@ -30,11 +30,15 @@ PACKAGES=(
rnp # Dep (rnpgp)
)
echo direnv: fetching source - weechat
mkdir -p /tmp/guix-build-weechat-3.2.drv-0
tar -C /tmp/guix-build-weechat-3.2.drv-0 -xJf $(guix build --source weechat)
use guix \
${ENVIRONMENTS[@]} --ad-hoc ${PACKAGES[@]} \
--with-debug-info=weechat\
--with-debug-info=libstrophe\
--with-debug-info=libsignal-protocol-c\
--with-debug-info=lmdb\
--with-debug-info=rnp\
clang:extra gdb
--with-debug-info=weechat \
--with-debug-info=libstrophe \
--with-debug-info=libsignal-protocol-c \
--with-debug-info=lmdb \
--with-debug-info=rnp \
clang clang:extra ccls gdb

@ -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;
};
}

84
deps/weechat.scm vendored

@ -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

@ -13,7 +13,7 @@ INCLUDES=-Ilibstrophe \
CFLAGS+=$(DBGCFLAGS) \
-fno-omit-frame-pointer -fPIC \
-std=gnu99 -gdwarf-4 \
-Wall -Wextra \
-Wall -Wextra -pedantic \
-Werror-implicit-function-declaration \
-Wno-missing-field-initializers \
-D_XOPEN_SOURCE=700 \
@ -21,9 +21,10 @@ CFLAGS+=$(DBGCFLAGS) \
CPPFLAGS+=$(DBGCFLAGS) \
-fno-omit-frame-pointer -fPIC \
-std=c++17 -gdwarf-4 \
-Wall -Wextra \
-Wall -Wextra -pedantic \
-Wno-missing-field-initializers \
$(INCLUDES)
# -DDOCTEST_CONFIG_DISABLE
LDFLAGS+=$(DBGLDFLAGS) \
-shared -gdwarf-4 \
$(DBGCFLAGS)
@ -39,46 +40,50 @@ PREFIX ?= /usr/local
LIBDIR ?= $(PREFIX)/lib
HDRS=plugin.hh \
plugin.h \
weechat.hh \
strophe.hh \
account.h \
buffer.h \
channel.h \
command.h \
completion.h \
config.h \
connection.h \
input.h \
message.h \
omemo.h \
pgp.h \
user.h \
util.h \
xmpp/stanza.h \
account.hh \
config.hh \
#### plugin.h \
#### account.h \
#### buffer.h \
#### channel.h \
#### command.h \
#### completion.h \
#### config.h \
#### connection.h \
#### input.h \
#### message.h \
#### omemo.h \
#### pgp.h \
#### user.h \
#### util.h \
#### xmpp/stanza.h \
SRCS=plugin.cpp \
weechat.cpp \
strophe.cpp \
account.c \
buffer.c \
channel.c \
command.c \
completion.c \
config.c \
connection.c \
input.c \
message.c \
omemo.c \
pgp.c \
user.c \
util.c \
xmpp/presence.c \
xmpp/iq.c \
account.cpp \
config.cpp \
#### account.c \
#### buffer.c \
#### channel.c \
#### command.c \
#### completion.c \
#### config.c \
#### connection.c \
#### input.c \
#### message.c \
#### omemo.c \
#### pgp.c \
#### user.c \
#### util.c \
#### xmpp/presence.c \
#### xmpp/iq.c \
DEPS=deps/diff/libdiff.a \
TSTS=$(patsubst %.cpp,tests/%.cc,$(filter %.cpp,$(SRCS))) tests/main.cc
OBJS=$(patsubst %.cpp,.%.o,$(patsubst %.c,.%.o,$(patsubst xmpp/%.c,xmpp/.%.o,$(SRCS))))
JOBS=$(patsubst tests/%.cc,tests/.%.o,$(TSTS))
all:
make depend
@ -87,7 +92,7 @@ all:
weechat-xmpp: $(DEPS) xmpp.so
xmpp.so: $(OBJS) $(DEPS) $(HDRS)
$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(DEPS) $(LDLIBS)
$(CXX) $(LDFLAGS) -o .$@ $(OBJS) $(DEPS) $(LDLIBS)
which patchelf >/dev/null && \
patchelf --set-rpath $(LIBRARY_PATH):$(shell realpath $(shell dirname $(shell gcc --print-libgcc-file-name))/../../../) xmpp.so && \
patchelf --shrink-rpath xmpp.so || true
@ -101,17 +106,14 @@ xmpp.so: $(OBJS) $(DEPS) $(HDRS)
xmpp/.%.o: xmpp/%.c
@$(CC) $(CFLAGS) -c $< -o $@
tests/.%.o: tests/%.cc
@$(CXX) $(CPPFLAGS) -c $< -o $@
deps/diff/libdiff.a:
git submodule update --init --recursive
cd deps/diff && ./configure
cd deps/diff && env -u MAKEFLAGS ./configure
$(MAKE) -C deps/diff CFLAGS=-fPIC
diff: deps/diff/libdiff.a
tests/run: xmpp.so $(JOBS)
$(CXX) $(CPPFLAGS) -o tests/run xmpp.so $(JOBS) $(LDLIBS)
tests/run: xmpp.so tests/main.cpp
$(CXX) $(CPPFLAGS) -o tests/run xmpp.so tests/main.cpp $(LDLIBS)
which patchelf >/dev/null && \
patchelf --set-rpath $(PWD):$(LIBRARY_PATH):$(shell realpath $(shell dirname $(shell gcc --print-libgcc-file-name))/../../../) tests/run && \
patchelf --shrink-rpath tests/run || true

@ -3,7 +3,10 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include "plugin.hh"
#include "weechat.hh"
#include "strophe.hh"
#include "config.hh"
#include "account.hh"
#define WEECHAT_XMPP_PLUGIN_NAME "xmpp"
#define WEECHAT_XMPP_PLUGIN_VERSION "0.2.0"
@ -11,23 +14,27 @@
namespace c {
extern "C" {
#include "plugin.h"
#include "config.h"
#include "account.h"
#include "connection.h"
#include "command.h"
#include "input.h"
#include "buffer.h"
#include "completion.h"
// #include "connection.h"
void connection__init();
// #include "command.h"
void command__init();
// #include "input.h"
int input__text_changed_cb(const void*, void*, const char*, const char*, void*);
// #include "buffer.h"
std::string buffer__typing_bar_cb(weechat::gui_bar_item&, weechat::gui_window&,
weechat::gui_buffer&, weechat::hashtable&);
// #include "completion.h"
void completion__init();
struct t_weechat_plugin *weechat_xmpp_plugin() {
return (struct t_weechat_plugin*)&*weechat::globals::plugin;
};
}
const char *weechat_xmpp_plugin_name() {
return WEECHAT_XMPP_PLUGIN_NAME;
};
}
const char *weechat_xmpp_plugin_version() {
return WEECHAT_XMPP_PLUGIN_VERSION;
};
}
}
}
@ -42,24 +49,21 @@ namespace weechat {
}
bool plugin::init(std::vector<std::string>) {
if (!c::config__init())
if (!this->m_config.emplace().read())
{
weechat::printf(nullptr, "%s: Error during config init",
this->name());
return false;
}
c::config__read();
c::connection__init();
c::command__init();
c::completion__init();
this->m_process_timer =
weechat::hook_timer(plugin::timer_interval_sec * 1000, 0, 0,
&c::account__timer_cb);
this->m_process_timer.emplace(plugin::timer_interval_sec * 1000, 0, 0,
[](int) { return weechat::errc::ok; });
if (!weechat::bar_search("typing"))
{
@ -69,12 +73,7 @@ namespace weechat {
"off", "xmpp_typing");
}
this->m_typing_bar_item =
weechat::bar_item_new("xmpp_typing",
(char* (*)(const void*, void*,
t_gui_bar_item*, t_gui_window*,
t_gui_buffer*, t_hashtable*))(
&c::buffer__typing_bar_cb));
this->m_typing_bar_item.emplace("xmpp_typing", weechat::gui_bar_item::build_callback());
weechat::hook_signal("input_text_changed", &c::input__text_changed_cb);
@ -86,13 +85,13 @@ namespace weechat {
this->m_process_timer.reset();
c::config__write();
this->m_config->write();
c::account__disconnect_all();
weechat::xmpp::account::disconnect_all();
c::account__free_all();
weechat::xmpp::globals::accounts.clear();
xmpp::shutdown();
::xmpp::shutdown();
return true;
}
@ -101,44 +100,32 @@ namespace weechat {
return plugin_get_name(*this);
}
weechat::plugin globals::plugin;
hook::hook(struct t_hook* hook)
: std::reference_wrapper<struct t_hook>(*hook) {
}
hook::~hook() {
weechat::unhook(*this);
}
gui_bar_item::gui_bar_item(struct t_gui_bar_item* item)
: std::reference_wrapper<struct t_gui_bar_item>(*item) {
weechat::xmpp::config& plugin::config() {
return *this->m_config;
}
gui_bar_item::~gui_bar_item() {
weechat::bar_item_remove(*this);
}
weechat::plugin globals::plugin;
}
extern "C" {
WEECHAT_PLUGIN_NAME(WEECHAT_XMPP_PLUGIN_NAME);
WEECHAT_PLUGIN_DESCRIPTION(N_("XMPP client protocol"));
WEECHAT_PLUGIN_AUTHOR("bqv <weechat@fron.io>");
WEECHAT_PLUGIN_VERSION(WEECHAT_XMPP_PLUGIN_VERSION);
WEECHAT_PLUGIN_LICENSE("MPL2");
WEECHAT_PLUGIN_PRIORITY(5500);
weechat::rc weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
WEECHAT_PLUGIN_NAME(WEECHAT_XMPP_PLUGIN_NAME)
WEECHAT_PLUGIN_DESCRIPTION(N_("XMPP client protocol"))
WEECHAT_PLUGIN_AUTHOR("bqv <weechat@fron.io>")
WEECHAT_PLUGIN_VERSION(WEECHAT_XMPP_PLUGIN_VERSION)
WEECHAT_PLUGIN_LICENSE("MPL2")
WEECHAT_PLUGIN_PRIORITY(5500)
weechat::errc weechat_plugin_init(struct t_weechat_plugin *plugin, int argc, char *argv[])
{
weechat::globals::plugin = (struct weechat::t_weechat_plugin*)plugin;
std::vector<std::string> args(argv, argv+argc);
return weechat::globals::plugin.init(args)
? WEECHAT_RC_OK : WEECHAT_RC_ERROR;
? weechat::ok : weechat::err;
}
weechat::rc weechat_plugin_end(struct t_weechat_plugin *)
weechat::errc weechat_plugin_end(struct t_weechat_plugin *)
{
return weechat::globals::plugin.end()
? WEECHAT_RC_OK : WEECHAT_RC_ERROR;
? weechat::ok : weechat::err;
}
}

@ -10,71 +10,40 @@
#include <vector>
#include <functional>
#include <optional>
#include <type_traits>
#include <cstring>
#include <stdexcept>
namespace weechat {
extern "C" {
#include <weechat/weechat-plugin.h>
typedef int rc;
typedef struct t_config_option config_option;
typedef struct t_config_section config_section;
typedef struct t_config_file config_file;
typedef struct t_gui_window gui_window;
typedef struct t_gui_buffer gui_buffer;
typedef struct t_gui_bar gui_bar;
//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;
//typedef struct t_weechat_plugin weechat_plugin;
}
#include "weechat.hh"
#include "config.hh"
class gui_bar_item : public std::reference_wrapper<struct t_gui_bar_item> {
public:
gui_bar_item(struct t_gui_bar_item* item);
~gui_bar_item();
template<typename Or_Input,
typename Func,
typename Input_Type = typename Or_Input::value_type,
typename Or_Output = std::invoke_result_t<Func, Input_Type>>
constexpr Or_Output operator>>= (Or_Input input, Func f) {
static_assert(std::is_invocable_v<decltype(f), Input_Type>,
"The function passed in must take type "
"(Or_Input::value_type) as its argument");
inline operator struct t_gui_bar_item* () const { return &this->get(); }
inline gui_bar_item& operator= (struct t_gui_bar_item* item_ptr) {
*this = std::move(gui_bar_item(item_ptr));
return *this;
}
};
class hook : public std::reference_wrapper<struct t_hook> {
public:
hook(struct t_hook* hook);
~hook();
inline operator struct t_hook* () const { return &this->get(); }
inline hook& operator= (struct t_hook* hook_ptr) {
*this = std::move(hook(hook_ptr));
return *this;
}
};
return input ? std::invoke(f, *input) : std::nullopt;
}
namespace weechat {
class plugin : public std::reference_wrapper<struct t_weechat_plugin> {
public:
plugin();
plugin(struct t_weechat_plugin* plugin);
explicit plugin(struct t_weechat_plugin* plugin);
bool init(std::vector<std::string> args);
bool end();
std::string_view name() const;
weechat::xmpp::config& config();
inline operator struct t_weechat_plugin* () const { return &this->get(); }
inline struct t_weechat_plugin* operator-> () const { return &this->get(); }
inline plugin& operator= (struct t_weechat_plugin* plugin_ptr) {
*this = std::move(plugin(plugin_ptr));
std::reference_wrapper<struct t_weechat_plugin>::operator=(*plugin_ptr);
return *this;
}
@ -83,13 +52,14 @@ namespace weechat {
private:
std::optional<hook> m_process_timer;
std::optional<gui_bar_item> m_typing_bar_item;
std::optional<weechat::xmpp::config> m_config;
};
namespace globals {
extern weechat::plugin plugin;
}
inline std::string_view plugin_get_name(struct t_weechat_plugin *plugin) {
inline const char *plugin_get_name(struct t_weechat_plugin *plugin) {
return globals::plugin->plugin_get_name(plugin);
}
@ -356,7 +326,9 @@ namespace weechat {
inline int util_timeval_cmp(struct timeval *tv1, struct timeval *tv2) {
return globals::plugin->util_timeval_cmp(tv1, tv2);
}
long long (*util_timeval_diff) (struct timeval *tv1, struct timeval *tv2);
inline long long util_timeval_diff(struct timeval *tv1, struct timeval *tv2) {
return globals::plugin->util_timeval_diff(tv1, tv2);
}
inline void util_timeval_add(struct timeval *tv, long long interval) {
return globals::plugin->util_timeval_add(tv, interval);
}
@ -555,53 +527,58 @@ namespace weechat {
}
inline struct t_config_file *config_new(const char *name,
int (*callback_reload)(const void *pointer,
void *data,
struct t_config_file *config_file),
const void *callback_reload_pointer,
void *callback_reload_data) {
return globals::plugin->config_new(globals::plugin, name, callback_reload, callback_reload_pointer, callback_reload_data);
}
inline struct t_config_section *config_new_section(struct t_config_file *config_file,
config_file::reload_callback& reload_cb) {
return globals::plugin->config_new(
globals::plugin, name,
[] (const void *pointer, void *, struct t_config_file *file) {
auto func = *reinterpret_cast<const config_file::reload_callback*>(pointer);
config_file file_(file);
return func(file_);
}, &reload_cb, nullptr);
}
inline struct t_config_section *config_new_section(struct t_config_file *file,
const char *name,
int user_can_add_options,
int user_can_delete_options,
int (*callback_read)(const void *pointer,
void *data,
struct t_config_file *config_file,
struct t_config_section *section,
const char *option_name,
const char *value),
const void *callback_read_pointer,
void *callback_read_data,
int (*callback_write)(const void *pointer,
void *data,
struct t_config_file *config_file,
const char *section_name),
const void *callback_write_pointer,
void *callback_write_data,
int (*callback_write_default)(const void *pointer,
void *data,
struct t_config_file *config_file,
const char *section_name),
const void *callback_write_default_pointer,
void *callback_write_default_data,
int (*callback_create_option)(const void *pointer,
void *data,
struct t_config_file *config_file,
struct t_config_section *section,
const char *option_name,
const char *value),
const void *callback_create_option_pointer,
void *callback_create_option_data,
int (*callback_delete_option)(const void *pointer,
void *data,
struct t_config_file *config_file,
struct t_config_section *section,
struct t_config_option *option),
const void *callback_delete_option_pointer,
void *callback_delete_option_data) {
return globals::plugin->config_new_section(config_file, name, user_can_add_options, user_can_delete_options, callback_read, callback_read_pointer, callback_read_data, callback_write, callback_write_pointer, callback_write_data, callback_write_default, callback_write_default_pointer, callback_write_default_data, callback_create_option, callback_create_option_pointer, callback_create_option_data, callback_delete_option, callback_delete_option_pointer, callback_delete_option_data);
bool user_can_add_options,
bool user_can_delete_options,
config_section::read_callback& read_cb,
config_section::write_callback& write_cb,
config_section::write_default_callback& write_default_cb,
config_section::create_option_callback& create_cb,
config_section::delete_option_callback& delete_cb) {
return globals::plugin->config_new_section(
file, name, user_can_add_options, user_can_delete_options,
[] (const void *pointer, void *, struct t_config_file *file,
struct t_config_section *section, const char *key, const char *value) {
auto func = *reinterpret_cast<const config_section::read_callback*>(pointer);
config_file file_(file);
config_section section_(section);
return func(file_, section_, key, value);
}, &read_cb, nullptr,
[] (const void *pointer, void *, struct t_config_file *file, const char *name) {
auto func = *reinterpret_cast<const config_section::write_callback*>(pointer);
config_file file_(file);
return func(file_, name);
}, &write_cb, nullptr,
[] (const void *pointer, void *, struct t_config_file *file, const char *name) {
auto func = *reinterpret_cast<const config_section::write_default_callback*>(pointer);
config_file file_(file);
return func(file_, name);
}, &write_default_cb, nullptr,
[] (const void *pointer, void *, struct t_config_file *file,
struct t_config_section *section, const char *key, const char *value) {
auto func = *reinterpret_cast<const config_section::create_option_callback*>(pointer);
config_file file_(file);
config_section section_(section);
return func(file_, section_, key, value);
}, &create_cb, nullptr,
[] (const void *pointer, void *, struct t_config_file *file,
struct t_config_section *section, struct t_config_option *option) {
auto func = *reinterpret_cast<const config_section::delete_option_callback*>(pointer);
config_file file_(file);
config_section section_(section);
config_option option_(option);
return func(file_, section_, option_);
}, &delete_cb, nullptr);
}
inline struct t_config_section *config_search_section(struct t_config_file *config_file,
const char *section_name) {
@ -609,32 +586,35 @@ namespace weechat {
}
inline struct t_config_option *config_new_option(struct t_config_file *config_file,
struct t_config_section *section,
const char *name,
const char *type,
const char *name, const char *type,
const char *description,
const char *string_values,
int min,
int max,
int min, int max,
const char *default_value,
const char *value,
int null_value_allowed,
int (*callback_check_value)(const void *pointer,
void *data,
struct t_config_option *option,
const char *value),
const void *callback_check_value_pointer,
void *callback_check_value_data,
void (*callback_change)(const void *pointer,
void *data,
struct t_config_option *option),
const void *callback_change_pointer,
void *callback_change_data,
void (*callback_delete)(const void *pointer,
void *data,
struct t_config_option *option),
const void *callback_delete_pointer,
void *callback_delete_data) {
return globals::plugin->config_new_option(config_file, section, name, type, description, string_values, min, max, default_value, value, null_value_allowed, callback_check_value, callback_check_value_pointer, callback_check_value_data, callback_change, callback_change_pointer, callback_change_data, callback_delete, callback_delete_pointer, callback_delete_data);
bool null_value_allowed,
config_option::check_callback& check_value_cb,
config_option::change_callback& change_cb,
config_option::delete_callback& delete_cb) {
return globals::plugin->config_new_option(
config_file, section,
name, type, description, string_values,
min, max, default_value, value, null_value_allowed,
[] (const void *pointer, void *, struct t_config_option *option, const char *value) {
auto func = *reinterpret_cast<const config_option::check_callback*>(pointer);
config_option option_(option);
return static_cast<int>(func(option_, value));
}, &check_value_cb, nullptr,
[] (const void *pointer, void *, struct t_config_option *option) {
auto func = *reinterpret_cast<const config_option::change_callback*>(pointer);
config_option option_(option);
return func(option_);
}, &change_cb, nullptr,
[] (const void *pointer, void *, struct t_config_option *option) {
auto func = *reinterpret_cast<const config_option::delete_callback*>(pointer);
config_option option_(option);
return func(option_);
}, &delete_cb, nullptr);
}
inline struct t_config_option *config_search_option(struct t_config_file *config_file,
struct t_config_section *section,
@ -784,7 +764,7 @@ namespace weechat {
template<typename... Args>
inline void printf(struct t_gui_buffer *buffer, const char *message, Args... args) {
return globals::plugin->printf_date_tags(
buffer, 0, NULL, message, args...);
buffer, 0, nullptr, message, args...);
}
template<typename... Args>
inline void printf_date_tags(struct t_gui_buffer *buffer, time_t date,
@ -824,21 +804,18 @@ namespace weechat {
void *callback_data) {
return globals::plugin->hook_command_run(globals::plugin, command, callback, callback_pointer, callback_data);
}
inline std::optional<hook> hook_timer(
inline struct t_hook *hook_timer(
long interval,
int align_second,
int max_calls,
int (*callback)(const void *pointer,
void *data,
int remaining_calls),
const void *callback_pointer = nullptr,
void *callback_data = nullptr) {
if (auto ptr = globals::plugin->hook_timer(
globals::plugin,
interval, align_second, max_calls,
callback, callback_pointer, callback_data))
return std::make_optional(hook(ptr));
return std::nullopt;
hook::timer_callback *callback) {
return globals::plugin->hook_timer(
globals::plugin,
interval, align_second, max_calls,
callback ? static_cast<hook::timer_fn>([] (const void *pointer, void *, int remaining_calls) {
auto func = *reinterpret_cast<const hook::timer_callback*>(pointer);
return static_cast<int>(func(remaining_calls));
}) : nullptr, callback, nullptr);
}
inline struct t_hook *hook_fd(int fd,
int flag_read,
@ -934,8 +911,9 @@ namespace weechat {
void *callback_data = nullptr) {
return globals::plugin->hook_signal(globals::plugin, signal, callback, callback_pointer, callback_data);
}
template<typename T>
inline int hook_signal_send(const char *signal, const char *type_data,
void *signal_data) {
T signal_data) {
return globals::plugin->hook_signal_send(signal, type_data, signal_data);
}
inline struct t_hook *hook_hsignal(const char *signal,
@ -1061,18 +1039,24 @@ namespace weechat {
}
inline struct t_gui_buffer *buffer_new(const char *name,
int (*input_callback)(const void *pointer,
void *data,
struct t_gui_buffer *buffer,
const char *input_data),
const void *input_callback_pointer,
void *input_callback_data,
int (*close_callback)(const void *pointer,
void *data,
struct t_gui_buffer *buffer),
const void *close_callback_pointer,
void *close_callback_data) {
return globals::plugin->buffer_new(globals::plugin, name, input_callback, input_callback_pointer, input_callback_data, close_callback, close_callback_pointer, close_callback_data);
gui_buffer::input_callback& input_cb,
gui_buffer::close_callback& close_cb) {
return globals::plugin->buffer_new(
globals::plugin,
name,
[] (const void *pointer, void *,
struct t_gui_buffer *buffer,
const char *input_data) {
auto func = *reinterpret_cast<const gui_buffer::input_callback*>(pointer);
gui_buffer buffer_(buffer);
return static_cast<int>(func(buffer_, input_data));
}, &input_cb, nullptr,
[] (const void *pointer, void *,
struct t_gui_buffer *buffer) {
auto func = *reinterpret_cast<const gui_buffer::close_callback*>(pointer);
gui_buffer buffer_(buffer);
return static_cast<int>(func(buffer_));
}, &close_cb, nullptr);
}
inline struct t_gui_buffer *buffer_search(const char *plugin, const char *name) {
return globals::plugin->buffer_search(plugin, name);
@ -1238,22 +1222,26 @@ namespace weechat {
inline struct t_gui_bar_item *bar_item_search(const char *name) {
return globals::plugin->bar_item_search(name);
}
inline std::optional<gui_bar_item> bar_item_new(
inline struct t_gui_bar_item *bar_item_new(
const char *name,
char *(*build_callback)(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),
const void *build_callback_pointer = nullptr,
void *build_callback_data = nullptr) {
if (auto ptr = globals::plugin->bar_item_new(
globals::plugin,
name, build_callback,
build_callback_pointer, build_callback_data))
return std::make_optional(gui_bar_item(ptr));
return std::nullopt;
gui_bar_item::build_callback& build_callback) {
return globals::plugin->bar_item_new(
globals::plugin,
name, [] (const void *pointer, void *,
struct t_gui_bar_item *item,
struct t_gui_window *window,
struct t_gui_buffer *buffer,
struct t_hashtable *extra_args) {
auto func = *reinterpret_cast<const gui_bar_item::build_callback*>(pointer);
gui_bar_item item_(item);
gui_buffer buffer_(buffer);
auto res = func(item_, window, buffer_, extra_args);
char *str = reinterpret_cast<char*>(
std::calloc(res.size() + 1, sizeof(char)));
std::copy(res.begin(), res.end(), str);
str[res.size()] = '\0';
return str;
}, &build_callback, nullptr);
}
inline void bar_item_update(const char *name) {
return globals::plugin->bar_item_update(name);

@ -2,13 +2,14 @@
// 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"
#include <cstdio>
xmpp_log_t* logger = nullptr;
#include "strophe.hh"
#include "strophe.ipp"
namespace xmpp {
context::context()
: context(xmpp_ctx_new(nullptr, logger)) {
extern "C" {
#include <strophe.h>
}
context::context(xmpp_ctx_ptr ptr)
@ -16,18 +17,80 @@ namespace xmpp {
}
context::context(xmpp_ctx_t *ptr)
: context(std::move(xmpp_ctx_ptr(
ptr, [this] (xmpp_ctx_t *ctx) {
xmpp_ctx_free(ctx);
}
))) {
: xmpp_ctx_ptr(ptr, xmpp_ctx_free) {
}
context::~context() {
this->reset(nullptr);
}
connection::connection(const context& context)
: connection(xmpp_conn_new(&*context)) {
}
connection::connection(xmpp_conn_ptr ptr)
: xmpp_conn_ptr(std::move(ptr)) {
}
connection::connection(xmpp_conn_t *ptr)
: xmpp_conn_ptr(ptr, xmpp_conn_release) {
}
connection::~connection() {
this->reset(nullptr);
}
void shutdown() {
xmpp_shutdown();
}
}
namespace xml {
extern "C" {
#include <libxml/xmlwriter.h>
}
template void set_error_context<FILE>(FILE*);
document::document(std::string_view text)
: m_ptr(xmlRecoverMemory(text.data(), text.size()))
, m_size(text.size()) {
}
document::~document() {
xmlFreeDoc(this->m_ptr);
}
document::node::node(xmlNodePtr ptr)
: m_ptr(ptr) {
}
std::string document::node::name() const {
return reinterpret_cast<const char*>(this->m_ptr->name);
}
std::optional<const document::node> document::root() {
xmlNodePtr root = xmlDocGetRootElement(this->m_ptr);
if (root)
return document::node(root);
else
return {};
}
document::operator bool () const {
return this->m_ptr;
}
std::string document::format() const {
if (!this->m_ptr)
throw xml::error("failed to parse xml");
std::unique_ptr<xmlChar> buf(
new xmlChar[this->m_size * 2]);
int size = -1;
xmlChar *bufPtr = &*buf;
xmlDocDumpFormatMemory(this->m_ptr, &bufPtr, &size, 1);
return std::string(bufPtr, bufPtr + size);
}
}

@ -6,23 +6,128 @@
#include <memory>
#include <functional>
#include <optional>
#include <string>
#include <string_view>
#include <stdexcept>
#include <any>
extern "C" {
namespace xmpp {
extern "C" {
#include <strophe.h>
}
}
namespace xmpp {
typedef std::unique_ptr<
xmpp_ctx_t,
std::function<void(xmpp_ctx_t*)>> xmpp_ctx_ptr;
template<typename UserData>
class logger : public xmpp_log_t {
private:
UserData& m_data;
public:
explicit logger<UserData>(UserData& data);
class level {
public:
level() = default;
constexpr level(const xmpp_log_level_t lvl) : value(lvl) { }
inline operator xmpp_log_level_t () const { return this->value; }
explicit operator bool () = delete;
constexpr bool operator== (level lvl) const { return this->value == lvl.value; }
constexpr bool operator!= (level lvl) const { return this->value != lvl.value; }
constexpr bool operator<= (level lvl) const { return this->value <= lvl.value; }
constexpr bool operator>= (level lvl) const { return this->value >= lvl.value; }
constexpr bool operator< (level lvl) const { return this->value < lvl.value; }
constexpr bool operator> (level lvl) const { return this->value > lvl.value; }
inline const char *name() const {
static const char *names[] = {"debug", "info", "warn", "error", nullptr};
return names[this->value];
}
private:
xmpp_log_level_t value;
};
inline static level debug = level(XMPP_LEVEL_DEBUG);
inline static level info = level(XMPP_LEVEL_INFO);
inline static level warn = level(XMPP_LEVEL_WARN);
inline static level error = level(XMPP_LEVEL_ERROR);
static void emit_weechat(UserData& data, const level level,
std::string_view area, std::string_view msg);
};
typedef std::unique_ptr<xmpp_ctx_t,
std::function<void(xmpp_ctx_t*)>> xmpp_ctx_ptr;
class context : public xmpp_ctx_ptr {
public:
context();
context(xmpp_ctx_ptr ptr);
context(xmpp_ctx_t *ptr);
template<typename UserData = void*>
explicit context(UserData& logger_data);
explicit context(xmpp_ctx_ptr ptr);
explicit context(xmpp_ctx_t *ptr);
~context();
inline operator xmpp_ctx_t* () { return this->get(); }
private:
std::any m_logger;
};
typedef std::unique_ptr<xmpp_conn_t,
std::function<void(xmpp_conn_t*)>> xmpp_conn_ptr;
class connection : public xmpp_conn_ptr {
public:
explicit connection(const context& context);
explicit connection(xmpp_conn_ptr ptr);
explicit connection(xmpp_conn_t *ptr);
~connection();
inline operator xmpp_conn_t* () { return this->get(); }
};
void shutdown();
}
namespace xml {
extern "C" {
#include <libxml/xmlwriter.h>
}
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 () {}
};
template<typename T>
void set_error_context(T *context);
class document {
protected:
class node {
public:
explicit node(xmlNodePtr ptr);
std::string name() const;
private:
const xmlNodePtr m_ptr;
};
public:
explicit document(std::string_view text);
~document();
std::optional<const node> root();
std::string format() const;
operator bool () const;
private:
const xmlDocPtr m_ptr;
const std::size_t m_size;
};
}

@ -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,4 +1,3 @@
#include <iostream>
#include <doctest/doctest.h>
#include "../plugin.hh"
@ -13,6 +12,7 @@ TEST_CASE("placeholder")
CHECK(argc != 1);
}
(void) argv;
//weechat::plugin c;
//CHECK(&c.name() == NULL);
}

Binary file not shown.

@ -1,11 +1,10 @@
#include <iostream>
#include <doctest/doctest.h>
#include "../strophe.hh"
TEST_CASE("create context")
{
xmpp::context ctx;
xmpp::context ctx(0);
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…
Cancel
Save